#include "PTL_DLT698.h"

#include "main.h"
#include "DataStore.h"
#include "ParaStore.h"
#include "DataColl.h"
#include "DataProc.h"
#include "UpComm.h"
#include "DnComm.h"
#include "HPLC.h"
#include "init.h"
#include "ctrl.h"
#include "Protect.h"
#include "ProcCtrl.h"
#include "signal.h"
#include "CRC_16.h"
#include <time.h>


#define	CASE_READ	1  //liruida 20240929
#define	CASE_WRITE	1   //liruida  20241010
//------------------------------------------wujiafei----------------------------------------
#define		max_feilvcount			12		//最大费率数 
#define		ee_histroydl_lenth		112
#define		max_dl_lenth		((max_feilvcount+1)*4)	//总和费率电量总字节数
 
/**
 * @brief  DLT698_接收步骤
 */
typedef enum DLT698_RCV_STEP
{
    DLT698_RCV_START,           //开始接收
    DLT698_RCV_LENGTH,          //接收长度
    DLT698_RCV_CONTENT,         //接收内容
} DLT698_RCV_STEP;

/**
 * @brief DLT698_收帧结构
 */
typedef struct DLT698_RCV_FRAME
{
    unsigned char ucStep;       //DLT698_接收步骤
    int dwRcvLen;               //接收帧长度
	int len_then;               //剩余接收帧长度
} DLT698_RCV_FRAME;


/**
 * @brief  DLT698_接收数组
 */
static DLT698_RCV_FRAME stDlt698Rcv[DLT698_PTL_HANDLE_NUM] = {
    DLT698_RCV_START,           //DLT698_接收步骤为开始接收
    0,                           //接收帧长度为0
	0
};

/**
 * @brief  接收延时计数器
 */
static unsigned int udwRcvtimerCounter[DLT698_PTL_HANDLE_NUM] = {0};

B08_Bit         bdata	System_Status_S;

B08_Bit			bdata	System_Status1_S;
#define	first_prog_flag			System_Status1_S.Bit.bit4	//首次编程标志


struct 	COMM_ADDRESS_FRM	near	Comm_Addr;	//通信地址(6) ＋crc（2）
struct 	COMMUNICATION_FRM	near	Uart[4]; //3个物理通道+1个内部通道
struct	FEIK_FRM		near	Feik;		//年时区数+日时段表数+日时段数+费率数+公共假日数+谐波次数+阶梯数+密钥总条数+CRC(2)
struct	UIP_FRM			near	Emu_Data;	//电压（3）+电流1（3）电流2（3）+功率1（3）+功率2（3）+功率因数（2）  //liruida 20241009
struct 	METERCONST_FRM		near	Meter;


uint08			near	Security_Type;	//通讯模式字00明文，01密文，其它：非安全模式
uint08			near	Security_Mode;	//安全传输方式


uint32			near 	HardFault_Flag;//HardFault标志
uint32			near 	Powerd_Flag;//掉电标志
uint32			near	LinkTimer[2][3];//应用链接超时定时器
uint08			near  	ConectType[2][3];	//当前链接的方式01:一般密码，02对称签名
uint16			near 	Reportstatus[3];//跟随上报状态字
uint08			near	FollowReport[3];//跟随上报对象编号(最新)

uint16			near 	CtrlProSta;	//控制命令执行状态字
uint16			near 	CtrlErrSta;	//控制命令错误状态字

uint16			near 	Reportstatus[3];//跟随上报状态字
uint16			near	Reportsta_Bk[3];//已处理上报状态字


struct	PARA_ESAM_FRM		near	Esam_Para;	//报警金额1限值(4)＋报警金额2限值(4)+变比(6)＋表号(6)+客户编号(6)+电卡类型(1)+身份认证时效(2)+Crc(2)
struct 	PARA_FEATUREWORD_FRM	near	Mode;
struct	PARA_REPORTMODE_FRM 	near	ModeEx;



unsigned char	near	ConectInfor[2][3][37];	//应用语境信息。同一物理通道涉及到通信帧尺寸、APDU尺寸，以最后一个应用连接为准，正在进行的通信不受影响)
unsigned char	near	TimeValid;	//时标合法性: 0-合法; 1-非法
unsigned char	near	TimeTag[11];	//时间标签：[0]CHOIC=00/01 [1:7]:T_DATE_TIME_S; [8:10]:TI;


uint32			near	Term_EnTimer; //终端认证定时器


unsigned short MaxApduLen[4];
unsigned char InBuf698[3*MAXRX];
unsigned char *AckBuf698=InBuf698+(MAXRX/2);
const uint16 ecode DefMaxApduLen[4] = { 2000, 2000, 2000, 2000 }; //默认APDU最大长度：字节
const uint08 ecode DefDepth = 21;			//默认的迭代深度 20 次

//698基本数据结构                     698数据类型 | 数据格式 | 645字节数
const BaseData code p_VOLTAGE     = { T_LONG_UNSIGNED,        { 0x01,  0,  2,  2 }, NULL }; //电压

const BaseData code p_COMB_ENERGY = { T_DOUBLE_LONG,          { 0x00,  0,  5,  4 }, NULL }; //组合电量(组合脉冲扩展到5字节)
const BaseData code p_COMB_ENERGY_G = { T_LONG64,             { 0x00,  0,  5,  8 }, NULL }; //高精度组合电量
const BaseData code p_SMPL_ENERGY2 ={ T_DOUBLE_LONG_UNSIGNED, { 0x00,  0,  4,  4 }, NULL }; //正向电量or反向电量
const BaseData code p_SMPL_ENERGY_G = { T_LONG64_UNSIGNED,    { 0x00,  0,  4,  8 }, NULL }; //高精度正向电量or反向电量
const ScalerUnit code s_COMB_ENERGY = { T_SCALER_UNIT, { 2, -2, U_kWh     } }; //组合电量    wujiafei  20241021
const ScalerUnit code s_COMB_ENERGY_G = { T_SCALER_UNIT, { 2, -4, U_kWh     } }; //组合电量   wujiafei  20241021

const unsigned long code p_ARRAY_VOLTAGE[]      = {
	T_ARRAY,      1,
	0x02010100, (unsigned long)&p_VOLTAGE,
	NULL };
const unsigned long code p_ARRAY_COMB_ENERGY[]  = {   //wujiafei  20241021
	T_ARRAY,      max_feilvcount+1, 
	0x00000000, (unsigned long)&p_COMB_ENERGY,
	0x00000100, (unsigned long)&p_COMB_ENERGY,
	0x00000200, (unsigned long)&p_COMB_ENERGY,
	0x00000300, (unsigned long)&p_COMB_ENERGY,
	0x00000400, (unsigned long)&p_COMB_ENERGY, 
	0x00000500, (unsigned long)&p_COMB_ENERGY,
	0x00000600, (unsigned long)&p_COMB_ENERGY, 
	0x00000700, (unsigned long)&p_COMB_ENERGY,
	0x00000800, (unsigned long)&p_COMB_ENERGY, 
	0x00000900, (unsigned long)&p_COMB_ENERGY,
	0x00000a00, (unsigned long)&p_COMB_ENERGY, 
	0x00000b00, (unsigned long)&p_COMB_ENERGY,
	0x00000c00, (unsigned long)&p_COMB_ENERGY };
const unsigned long code p_ARRAY_COMB_ENERGY_G[]  = {   //wujiafei  20241021
	T_ARRAY,      max_feilvcount+1, 
	0x00F00000, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00100, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00200, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00300, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00400, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00500, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00600, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00700, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00800, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00900, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00a00, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00b00, (unsigned long)&p_COMB_ENERGY_G,
	0x00F00c00, (unsigned long)&p_COMB_ENERGY_G };

const ScalerUnit code s_VOLTAGE     = { T_SCALER_UNIT, { 2, -1, U_V       } }; //电压
const BaseData code p_COMADDR     = { T_OCTET_STRING,         { 0x00,  0,  6,  6 }, NULL }; //通信地址
const BaseData code p_METERID     = { T_OCTET_STRING,         { 0x00,  0,  6,  6 }, NULL }; //表号

// =========== 7.3.1　电能量接口类（class_id=1） =========== 
//组合电量的类初始化    wujiafei  20241021
const AttrMethod code CombEnergy[] = {
	{ 0x80+2, (unsigned long)&p_ARRAY_COMB_ENERGY }, //总及费率电能量数组, 目前支持总，1~4费率，共计5个元素
	{ 0x80+3, (unsigned long)&s_COMB_ENERGY },       //换算及单位
	{ 0x80+4, (unsigned long)&p_ARRAY_COMB_ENERGY_G }, //高精度总及费率电能量数组, 目前支持总，1~4费率，共计5个元素
	{ 0x80+5, (unsigned long)&s_COMB_ENERGY_G },       //高精度换算及单位
//	{ 0x80+6, (unsigned long)&p_ARRAY_COMB_ENERGY_G6 }, //高精度总及费率电能量数组, 目前支持总，1~4费率，共计5个元素
//	{ 0x80+7, (unsigned long)&s_COMB_ENERGY_G7 },       //高精度换算及单位
	{ 0xFF, 0xFFFFFFFF },       //属性结束标志
//	{ 1, 0 },           //复位
//	{ 2, 0 },           //执行
	{ NULL, NULL } };
// =========== 7.3.3　分相变量接口类（class_id=3） =========== 
//电压
const AttrMethod code ArrVoltage[] = { 
	{ 0x80+2, (unsigned long)&p_ARRAY_VOLTAGE }, //2. 分相数值组∷=array 分相数值
	{ 0x80+3, (unsigned long)&s_VOLTAGE },       //3. 换算及单位∷=Scaler_Unit
	{ 0xFF, 0xFFFFFFFF },
//	{ 1, 0 },
//	{ 2, 0 },
	{ NULL, NULL } };
	

const unsigned long code p_COMM_ADDR[]     = {
	T_OCTET_STRING,       6,
	0x04000401, (unsigned long)&p_COMADDR,
	NULL };	

const unsigned long code p_METER_ID[]     = {
	T_OCTET_STRING,       8,
	0x04000402, (unsigned long)&p_METERID,
	NULL };	
	
//通讯地址
const AttrMethod code CommAddr[] = { 
	{ 0xC0+2, (unsigned long)&p_COMM_ADDR },
//	{ 0x00+3, 0 },
	{ 0xFF, 0xFFFFFFFF },
//	{ 1, 0 },
//	{ 2, 0 },
	{ NULL, NULL } };

//表号
const AttrMethod code MeterID[] = { 
	{ 0xC0+2, (unsigned long)&p_METER_ID },
//	{ 0x00+3, 0 },
	{ 0xFF, 0xFFFFFFFF },
//	{ 1, 0 },
//	{ 2, 0 },
	{ NULL, NULL } };

//-------------------------wujiafei 结构体定义及初始化----------------------------------
struct PLUSE_FRM						//小端存储(51为大端)
{
	union B32_B08_2	Pluse[max_feilvcount+1];	//总和各费率脉冲尾数
	union B32_B08_2	UPluse;				//本月用电量(脉冲数)
	union B32_B08_2	JUPluse;			//本月用电量(阶梯结算)(脉冲数)
	union B16_B08	Crc16;		
};

 struct	PLUSE_FRM	near	Fw		;//正向有功脉冲数和校验
 struct	PLUSE_FRM	near	Bk		;//反向有功脉冲数和校验
	
	

//================ 支持的对象编码总表 ================
const Map code MapTab[] = 
{
	{ 0x0000,  0x8000, (uint08 *)(&CombEnergy    ) }, //组合有功电能   wujiafei  20241021
	//{ 0x0010,  0x8000, (uint08 *)(&ForwEnergy    ) }, //正向有功电能
	//{ 0x0020,  0x8000, (uint08 *)(&RevsEnergy    ) }, //反向有功电能
	               
//变量类对象：       
	{ 0x2000,  0x4040, (uint08 *)(&ArrVoltage    ) }, //电压
//参变量类对象：
	{ 0x4001,  0x8100, (uint08 *)(&CommAddr      ) }, //通讯地址
	
	{ 0x4002,  0x8400, (uint08 *)(&MeterID       ) }, //表号
};




int32 Byte2Int(uint08* byte)
{
  return (int32)(byte[3]+((uint32)byte[2]<<8) + ((uint32)byte[1]<<16) +((uint32)byte[0]<<24)) ;
}

unsigned char Hex_To_Bcd( unsigned char value )
{
	return ( ((value/10)<<4)+(value%10) );
}

unsigned char Bcd_To_Hex( unsigned char value )
{
	return ( ((value&0xF0)>>4)*10+(value&0x0F) );
}

/*============================================================================*
	函数：	void Hex2Bcd( unsigned char *Hexop, unsigned char *BCDopt, unsigned char Len );
	功能：	多字节HEX转换BCD
	参数：	*Hexop  HEX 初始值为待转化的高字节地址； 
			*BCDopt  BCD 初始值为待转化的高字节地址； 
			Len  长度，最大4个字节
  返回值:	无
*============================================================================*/	
void Hex2Bcd( unsigned char *Hexop, unsigned char *BCDopt, unsigned char Len )
{	
	unsigned char i,m;
	unsigned long long hex_temp;
	unsigned char code temp1[8]={0,8,16,24,32,40,48,56};
	
	if(Len>8)
		return;
	hex_temp=0;
	for(i=0;i<Len;i++)
	{
		hex_temp+=(unsigned long long)((unsigned long long)Hexop[i]<<temp1[Len-1-i]);		
	}
	
	for(i=0; i<Len;i++)
	{
		m = (unsigned char)(hex_temp % 100);
		BCDopt[Len-1-i]=Hex_To_Bcd(m);							//转换为BCD格式
		hex_temp/=100;
	}
	return;
}


/*============================================================================*
	函数：	void Bcd2Hex( uint08 *BCDopt, uint08 *HEXopt, uint08 Len );
	功能：	多字节BCD转换HEX
	参数：	*BCDopt  BCD 初始值为待转化的高字节地址； 
			*HEXopt  HEX 初始值为待转化的高字节地址；
			Len  长度，最大4个字节
  返回值:	无
*============================================================================*/	
void Bcd2Hex( unsigned char *BCDopt, unsigned char *HEXopt, unsigned char Len )
{	
	unsigned long long hex_temp;
	unsigned long long code temp0[8]={1,100,10000,1000000,100000000,10000000000,1000000000000,100000000000000};	
	unsigned char code temp1[8]={0,8,16,24,32,40,48,56};
	unsigned char i;
	if(Len>8)
		return;
	hex_temp=0;
	for(i=0;i<Len;i++)
	{
		hex_temp+=(unsigned long long)(Bcd_To_Hex(BCDopt[Len-1-i]))*temp0[i];		
	}
	for(i=0;i<Len;i++)
	{
		HEXopt[Len-1-i]=(unsigned char)(hex_temp>>temp1[i]);
	}	
	return;
}

void Bcd2Hex_LS( unsigned char *BCDopt, unsigned char *HEXopt, unsigned char Len )		//大端Bcd变成小端Hex
{	
	Bcd2Hex( BCDopt, HEXopt, Len );
	Inverse( HEXopt, Len );
	return;
}


uint32 Byte2uInt(uint08* byte)
{
  return byte[3]+((uint32)byte[2]<<8) + ((uint32)byte[1]<<16) +((uint32)byte[0]<<24) ;
}

uint16 Byte2uShort(uint08* byte)
{
  return byte[1]+((uint16)byte[0]<<8);
}

void Int2Byte(uint32 datatemp,uint08* Buff)
{
  Buff[3] = datatemp ;
  Buff[2] = (datatemp>>8) ;
  Buff[1] = (datatemp>>16) ;
  Buff[0] = (datatemp>>24) ;
}

void Short2Byte(uint16 datatemp,uint08* Buff)
{
  Buff[1] = datatemp ;
  Buff[0] = (datatemp>>8) ;
}


//----------------------------------------------------------------------------
unsigned char GetApduByte( unsigned char *pBuf )
//取数为任意区间，在APDU的2K区间时，特殊处理
{
	//if( (unsigned long)(pBuf) >= 0x20006000 ) return 0;   liruida q 20240914
	return (pBuf[0]);
}


unsigned char PutApduByte( unsigned char *pBuf, unsigned char Value )
//存数仅限APDU的2K区间, 区间外不写入
{
	//if( (unsigned long)(pBuf) >= 0x20006000 ) return 0;   liruida q 20240918
	pBuf[0] = Value;
	return 0;
}

unsigned char MoveByte( unsigned char *MoveBuf, unsigned int Get, unsigned int Put )
{
	unsigned char Temp08;
	
	Temp08 = GetApduByte( MoveBuf+Get );
	PutApduByte( MoveBuf+Put, Temp08 );
	
	return 0;
}


unsigned char CopyApdu( unsigned char *Des, unsigned char *Src, unsigned int Len )
//从Src(APDU区)取数到Des(非APDU区)
{
	unsigned int k;
	
	for( k=0; k<Len; k++ )
	{
		Des[k] = GetApduByte( Src+k );
	}
	
	return 0;
}


unsigned char CopyApduInv( unsigned char *Des, unsigned char *Src, unsigned int Len )
//从Src(APDU区)取数到Des(非APDU区)
{
	unsigned int k;
	
	for( k=0; k<Len; k++ )
	{
		Des[k] = GetApduByte( Src+Len-1-k );
	}
	
	return 0;
}


unsigned char MoveForword( unsigned char *MoveBuf, unsigned int Len, unsigned int Total )
//MoveBuf:起始地址; Len:位移的字节数; Total:数据总长度
{
	unsigned int k;
	
	for( k=0; k<Total; k++ ) //前移“可变字节的长度”
	{
		MoveByte( MoveBuf, Len+k, k );
	}
	
	return 0;
}

//----------------------------------------------------------------------------

unsigned short Crc_16Bits_698( unsigned short Init, unsigned char *buf, unsigned int len ) 
{
	unsigned short i, current, CRC16;
	unsigned char j;
	
	CRC16 = Init;
	
	for( i=0; i<len; i++ )
	{
	    current = buf[i];
	    for (j = 0; j < 8; j++) 
	    { 
	        if ((CRC16 ^ current) & 0x0001)
	            CRC16 = (CRC16 >> 1) ^ 0x8408;
	        else 
	            CRC16 >>= 1; 
	        current >>= 1;            
	    }
	}
	
	CRC16 ^= 0xffff;
	
	return CRC16;
}


unsigned char FindOI( uint08 *OI )
{
	unsigned char i;
	uint16 curOI;
	curOI = Byte2uShort(OI);
	for( i=0; i<(sizeof(MapTab)/sizeof(Map)); i++ )
	{    
		if( curOI == MapTab[i].OI )
		{
			return i;
		}
	}
	
	return 0xFF;
}

//类型转换最大支持4字节
void Bcd2Hex698Translate( unsigned char *BCDopt, unsigned char *HEXopt, unsigned char Len )
{
	unsigned char i;
	union S32_B08 Temp32;
	union B64_B08_2 Temp64;
	Int2Byte(0,Temp32.B08);
  
	if( BCDopt[0]&0x80 )
	{
		BCDopt[0] &= (~0x80	);
		
		if( Len == 8 )
		{
			Bcd2Hex_LS( BCDopt, Temp64.B08, Len );
			Temp64.B64 = ~Temp64.B64+1;
			Exchange( HEXopt, Temp64.B08, Len );
		}
		else
		{
			Bcd2Hex( BCDopt, HEXopt, Len );	
			
			for( i=0;i<Len;i++ )
			{
				Temp32.B08[3-i] = HEXopt[Len-1-i];
			}
                	
			Int2Byte(Byte2Int(Temp32.B08)*-1,Temp32.B08);
                	
			for( i=0;i<Len;i++ )
			{
				HEXopt[Len-1-i] = Temp32.B08[3-i];
			}
		}
	}
	else
	{
		Bcd2Hex( BCDopt, HEXopt, Len );	
	}
}


void Hex2Bcd698Translate( unsigned char *Hexopt, unsigned char *BCDopt, unsigned char Len )
{
	unsigned char i;
	union S32_B08 Temp32;
	
	int32 i32;
	Int2Byte(0,Temp32.B08);
	i32 = 0;
  
	for( i=0;i<Len;i++ )
	{
		Temp32.B08[3-i] = Hexopt[Len-1-i];
	}
  
	i32 = Byte2Int(Temp32.B08);
	if( i32 < 0 )
	{
		i32 = i32*-1;
		Int2Byte(i32,Temp32.B08);
    
		for( i=0;i<Len;i++ )
		{
			Hexopt[Len-1-i] = Temp32.B08[3-i];
		}		
		Hex2Bcd( Hexopt, BCDopt, Len );	
		BCDopt[0] |= 0x80;
	}
	else
	{	
		Hex2Bcd( Hexopt, BCDopt, Len );	
	}
}



void Inverse( unsigned char *Buf, unsigned char Len )
{
	unsigned char i, Temp08;
	
	for( i=0; i<Len/2; i++ )
	{
		Temp08 = Buf[i];
		Buf[i] = Buf[Len-1-i];
		Buf[Len-1-i] = Temp08;//交换数据
	}
}


void BitInverse( unsigned char *InvBuf, unsigned char Len )
{
	unsigned char i, k, n, Temp08;
	
	for( n=0; n<Len; n++ )
	{
		Temp08 = 0;
		k = 1;
		for( i=0; i<8; i++ )
		{
			Temp08 <<= 1;
			if( InvBuf[n]&k ) Temp08 |= 1;
			k <<= 1;
		}
		InvBuf[n] = Temp08;
	}
	
	Inverse( InvBuf, Len );
}




unsigned char SendByte( unsigned char Ch, unsigned char AnByte )
{
	unsigned char Result;
	
	if( Uart[Ch].Total698 >= (MAXRX/2) ) //APDU超过最大存储空间, 不允许存储
	{
		Uart[Ch].FrmFull = 1;
		return 1;
	}
	
	if( CHIN != Ch )
	{
		Result = PutApduByte( AckBuf698+Ch*MAXRX+Uart[Ch].Total698, AnByte );
		if( Result ) return 1;
	}

	Uart[Ch].Total698++;
	
	return 0;
}

unsigned char SendStr( unsigned char Ch, unsigned char *AnByte, unsigned int Len )
{
	unsigned int  i, num;
	unsigned char result;
	
	num = Len&0x7FFF;
	
	if( (Len&0x8000) == 0 )	//正序传输
	{
		for( i=0; i<num; i++ )	result = SendByte( Ch, GetApduByte(AnByte+i) );
	}
	else	//反序传输
	{
		for( i=0; i<num; i++ )	result = SendByte( Ch, GetApduByte(AnByte+num-1-i) );
	}
	
	return result;
}

unsigned char ClockHex2Bcd( unsigned char *BcdClk, unsigned char *HexClk, unsigned char Len )
//输入HexClk = YYYYMMDDWW or YYYYMMDDhhmmss; 
//输出BcdClk = WWDDMMYY or ssmmhhDDMMYY; 
//返回值=0:正常, FF:存在无效值
{
	unsigned char i, n, flag=0;
	unsigned short Year;
	
	CopyApdu( BcdClk, HexClk, Len );
	for( n=0; n<Len; n+=i )
	{
		if( n == 0 )
		{
			i = 2;
			Year = Byte2uShort(BcdClk);
			if( 0xFFFF == Year ) 
			{
				flag = 0xFF;
				continue;
			}
			
			if( (2000 > Year) || (Year > 2099) )
			{
				flag = 0xFF;
				if( (0 == Year) && (0 == BcdClk[2]) )
					memset( BcdClk, 0x00, 2 );
				else if( (9999 == Year) && (99 == BcdClk[2]) )
					memset( BcdClk, 0x99, 2 );
				else
					memset( BcdClk, 0xFF, 2 );
				continue;
			}
		}
		else
		{
			i = 1;
			if( (0xFF == BcdClk[n]) || (99 < BcdClk[n]) )
			{
				flag = 0xFF;
				continue;
			}
		}
		
		Hex2Bcd( BcdClk+n, BcdClk+n, i );
	}
	
	Inverse( BcdClk, Len );
	
	if( (0xFF != flag) && (7 == Len) )
	{
		if( JudgeClockNoWeek(0, BcdClk, 6) ) flag = 0xFF; //时间非法
	}
	
	return flag;
}


void Exchange(unsigned char *BufA, unsigned char *BufB, unsigned char Len )
{
	unsigned char n;
	for( n=0; n<Len; n++ )
	{
		BufA[n] = BufB[Len-1-n];//交换数据
	}
}



uint08 IsBCD( uint08 Value )
{
	if( ((Value&0xF0)<=0x90) && ((Value&0x0F)<=0x09) )
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

unsigned char IsMultiBcd( unsigned char *Buf, unsigned char Len )
//return: 0: BCD; 1: no BCD
{
	unsigned char i;
	
	for( i=0; i<Len; i++ )
	{
		if( IsBCD(Buf[i]) != 0x00 )		return 1;
	}
	
	return 0;
}


void ClockBcd2Hex( unsigned char *HexClk, unsigned char *BcdClk, unsigned char Len )
//输入BcdClk = WWDDMMYY or mmhhDDMMYY or ssmmhhDDMMYY; 
//输出HexClk = YYYYMMDDWW or YYYYMMDDhhmmss; 
{
	unsigned char i, n;
	
	CopyApduInv( HexClk+1, BcdClk, Len );
	
	for( n=0; n<(Len+1); n+=i )
	{
		if( n == 0 )
		{
			i = 2;
			if( (HexClk[2] == 0) || (HexClk[2] == 0x99) || (HexClk[2] == 0xFF) ) //MM
			{
				if( HexClk[2] == 0x99 ) Short2Byte( 9999, HexClk );
				else memset( HexClk, HexClk[2], 2 );
			}
			else
			{
				HexClk[0] = 0x20;
				Bcd2Hex( HexClk, HexClk, 2 ); //YYYY
			}
		}
		else
		{
			i = 1;
			if( 0xFF != HexClk[n] )
			{
				HexClk[n] = Bcd_To_Hex( HexClk[n] );
			}
		}
	}
}



//获取字节数，支持长度域可变
unsigned short GetDataLen( unsigned char *Frame, unsigned short *nBytes )
{
	unsigned short Len=0;
	
	if( (GetApduByte(Frame+0)&0x80) == 0 )    //0x80:10000000
	{
		Len = GetApduByte(Frame+0); //无长度域
		if( nBytes ) *nBytes += 1;
	}
	else 
	{
		if( (GetApduByte(Frame+0)&0x7F) == 1 )    //0x7F:01111111 
		{
			Len = GetApduByte(Frame+1); //长度字节
			if( nBytes ) *nBytes += 2;
		}
		else 
		{
			CopyApdu( (uint08*)(&Len), Frame+1, 2 );
			Inverse((uint08*)(&Len),2);    
			if( nBytes ) *nBytes += 3;
		}
	}
	
	return Len;
}


typedef struct {
	unsigned char Ch;		//通信通道号
	unsigned long *Type;	//数据类型列表
	unsigned char *RtBuf;	//输入645/698格式数据
	unsigned char *OutBuf;	//输出698/645格式数据
	unsigned char Dir;		//转换方向0x00:645->698, 0x01:698->645
	unsigned char Result;	//0:正确; 其他值：错误代码
}DRW_STRUCT;


//基本数据类型的格式化输出
unsigned int R_NORMAL( DRW_STRUCT *In )
//返回值：0=类型错; 1=越界; ≥2=正常
{
	unsigned char i, n, Type, Temp08;
	unsigned int k;
	unsigned char Buf[16];
	unsigned char Format; //数据格式：Bit0: BCD; Bit1：符号位
	         char Offset; //645起始位
	unsigned char Len645; //645字节数
	unsigned char Len698; //698字节数
	
	In->Result = 0; //缺省结果为正常

	Type = In->Type[0];
	Format = *( ((uint08 *)(In->Type+1))+0 );
	Offset = *( (( int08 *)(In->Type+1))+1 );
	Len645 = *( ((uint08 *)(In->Type+1))+2 );
	Len698 = *( ((uint08 *)(In->Type+1))+3 );
	
	k = 0;
	if( In->Dir == 0 )//get
	{
		k = Uart[In->Ch].Total698;
		
		SendByte( In->Ch, Type ); //数据类型
		if( (T_OCTET_STRING == Type) 
		|| (T_VISIBLE_STRING == Type) 
		|| (T_BIT_STRING == Type) 
		|| (T_RN == Type) ) 
		{
			if( Len698 > 127 ) SendByte( In->Ch, 0x81 );
			SendByte( In->Ch, Len698 ); //数据长度
		}

		if( (Format&1) == 0 ) //direct output
		{
			if( Format&4 ) //hex to Ascii
			{
				for( n=0; n<Len645*2; n++ )
				{
					if( (n&1) == 0 )
					{
						Temp08 = GetApduByte( In->RtBuf+Offset+Len645-1-(n/2) );
						i = (Temp08>>4);
					}
					else
					{
						i = (Temp08&0x0F);
					}
					
					SendByte( In->Ch, i<=9?(i+'0'):(i+0x37) );
				}
			}
			else
			{
				if( T_BIT_STRING == Type )
				{
					Len698 /= 8;
					CopyApdu( Buf, In->RtBuf+Offset, Len698 );
					BitInverse( Buf, Len698 );
					SendStr ( In->Ch, Buf, Len698|0x8000 );
				}
				else if( (unsigned long*)(&p_COMB_ENERGY) == In->Type  ) //组合电量 普通精度 4字节   wujiafei 20241021
				{
//					union S64_B08_2 TempS;
//					
//					memcpy( TempS.B08, In->RtBuf+Offset, 5 );
//					if( TempS.B08[4]&0x80 ) memset( TempS.B08+5, 0xFF, 3 );
//					else memset( TempS.B08+5, 0x00, 3 );
//					
//					//TempS.S64 /= Meter.Const_H;   
//					
//					SendStr( In->Ch, (uint08*)(TempS.B08), Len698|0x8000 );
					SendStr( In->Ch, In->RtBuf+Offset, Len698);
				}
				else if( (unsigned long*)(&p_COMB_ENERGY_G) == In->Type  ) //组合电量 高精度 8字节
				{
					union S64_B08_2 TempS;
					
					memcpy( TempS.B08, In->RtBuf+Offset, 5 );
					if( TempS.B08[4]&0x80 ) memset( TempS.B08+5, 0xFF, 3 );
					else memset( TempS.B08+5, 0x00, 3 );
					
					TempS.S64 = (TempS.S64*100/Meter.Const_H);
					
					SendStr( In->Ch, (uint08*)(TempS.B08), Len698|0x8000 );
					
				}
				else if( (unsigned long*)(&p_SMPL_ENERGY2) == In->Type  ) //正向电量/反向电量 普通精度 4字节
				{
					union B32_B08_2 Temp32;
					
					memcpy( Temp32.B08, In->RtBuf+Offset, 4 );
					Temp32.B32 /= Meter.Const_H;
					
					SendStr( In->Ch, (uint08*)(Temp32.B08), Len698|0x8000 );
				}
				else if( (unsigned long*)(&p_SMPL_ENERGY_G) == In->Type  ) //正向电量/反向电量 高精度 8字节
				{
					union B64_B08_2 TempU;
					
					memcpy( TempU.B08, In->RtBuf+Offset, 4 );
					memset( TempU.B08+4, 0x00, 4 );
					TempU.B64 = (TempU.B64*100/Meter.Const_H);
					
					SendStr( In->Ch, (uint08*)(TempU.B08), Len698|0x8000 );
				}
				else
				{
					for( n=0; n<Len698; n++ )
					{
						if( (Len698 > Len645) && (n < (Len698-Len645)) ) SendByte( In->Ch, 0 );
						else SendByte( In->Ch, In->RtBuf[Offset+Len698-1-n] );
					}
	
					if( (T_CSD == Type) && GetApduByte(In->RtBuf+Offset+Len645-1) ) //ROAD
					{
						SendStr( In->Ch, In->RtBuf+Offset+Len645, 5|0x8000 );
						Len645 += 5;
						Len698 += 5;
					}
				}
			}
		}
		else //645数据为BCD码
		{
			if( (T_DATE == Type) //日期，5字节，YYYYMMDDWW
			 || (T_DATE_TIME_S == Type) ) //日期时间，7字节，YYYYMMDDhhmmss
			{
				i = GetApduByte( In->RtBuf+Offset+Len645-2 ); //取得月份，用于填充千年
				ClockBcd2Hex( Buf, In->RtBuf+Offset, Len645 );     //liruida 20241015
				SendStr( In->Ch, Buf, Len645+1 );
				
				if( (0x00 == i) || (0x99 == i) ) //月份为00或99
				{
					if( (3 == Len645) ) //补周or补秒，645切换时间为5字节
					{
						SendByte( In->Ch, Bcd_To_Hex(i) );
					}
				}
				
				if( 5 == Len645 ) //补秒，645切换时间为5字节
				{
					SendByte( In->Ch, 0xFF );
				}
			}
			else
			{
				i = 0;
				if( Len698 > Len645 ) 
				{
					i += (Len698-Len645);
					memset( Buf, 0, i );
				}

				CopyApduInv( Buf+i, In->RtBuf+Offset, Len645 );       //liruida  20241015
				
				if( Len698 >= Len645 ) //698 longer or equal
				{
					if( (Format&2) && (Buf[Len698-Len645]&0x80) )
					{
						Buf[Len698-Len645] &= 0x7F;
						Buf[0] |= 0x80;
						Bcd2Hex698Translate( Buf, Buf, Len698 );      //liruida   20241015
					}
					else
					{
						Bcd2Hex( Buf, Buf, Len698 );                  //liruida    20241015
					}
	
					SendStr( In->Ch, Buf, Len698 );
				}
				else //645 longer
				{
					Bcd2Hex698Translate( Buf, Buf, Len645 );          //liruida    20241015
					SendStr( In->Ch, Buf+(Len645-Len698), Len698 );
				}
			}
		}

		k = Uart[In->Ch].Total698-k;

		k += Len698;
		In->OutBuf += k;
		In->RtBuf += Len645;
	}
	else //set
	{
		if( Type != GetApduByte(In->RtBuf+0) ) 
		{
			In->Result = DAR_DISMATCH; //类型不匹配
			return k; 
		}
		k += 1; //数据类型
		
		if( (T_OCTET_STRING == Type) || (T_VISIBLE_STRING == Type) || (T_BIT_STRING == Type) )
		{
			if( Len698 != GetApduByte(In->RtBuf+1) ) 
			{
				In->Result = DAR_OVERARRAY; //越界
				return k;
			}
			k += 1; //数据长度
		}

		if( In->Dir == 1 )
		{
			if( (Format&1) == 0 ) //direct output
			{
				if( Format&4 ) //hex to Ascii
				{
					for( n=0; n<Len645*2; n++ )
					{
						Temp08 = GetApduByte( In->RtBuf+k+n );
						Temp08 = Temp08 <= '9'? (Temp08-'0'):(Temp08-0x37);
						if( (n&1) == 0 ) 
						{
							i = (Temp08<<4);
						}
						else
						{
							i += Temp08;
							In->OutBuf[ Offset+Len645-1-(n/2) ] = i;
						}
					}
				}
				else
				{
					if( T_BIT_STRING == Type )
					{
						Len698 /= 8;
						CopyApdu( Buf, In->RtBuf+k, Len698 );
						BitInverse( Buf, Len698 );
						Exchange( In->OutBuf+Offset, Buf, Len698 );
					}
					else
					{
						for( n=0; n<Len645; n++ )
						{
							if( n < Len698 )
								In->OutBuf[Offset+n] = GetApduByte( In->RtBuf+k+Len698-1-n );
							else
								In->OutBuf[Offset+n] = 0x00;
						}
						
						if( (T_CSD == Type) && (In->OutBuf[Offset+Len645-1]) ) //CHOICE = ROAD
						{
							if( (In->OutBuf[Offset+Len645-1] > 1) || (GetApduByte( In->RtBuf+k+Len645 ) != 1) )
							{
								In->Result = DAR_OVERARRAY; //越界
								return k;
							}
							
							CopyApduInv( In->OutBuf+Offset+Len645, In->RtBuf+k+Len645, 5 );         //liruida  20241015

							Len645 += 5;
							Len698 += 5;
						}
					}
				}
			}
			else
			{
				if( (T_DATE == Type) //日期，5字节，YYYYMMDDWW
				 || (T_DATE_TIME_S == Type) ) //日期时间，7字节，YYYYMMDDhhmmss
				{
					if( (0xFFFF != Byte2uShort(In->RtBuf+k)) && (0xFF == In->RtBuf[k+2]) ) //月份为FF，年必须为FFFF
					{
						In->Result = DAR_OTHER; //其他
						return k;
					}
					
					if( (0x0000 != Byte2uShort(In->RtBuf+k)) && (0x00 == In->RtBuf[k+2]) ) //月份为00，年必须为0000
					{
						In->Result = DAR_OTHER; //其他
						return k;
					}
					
					ClockHex2Bcd( Buf, In->RtBuf+k, Len698 );                    //liruida  20241015
					memcpy( In->OutBuf+Offset, Buf+(Len698-Len645-1), Len645 );
				}
				else
				{
					memset( Buf, 0, 8 );
					CopyApdu( Buf+4-Len698, In->RtBuf+k, Len698 );
					
					for( n=0; n<Len698; n++ ) 
					{
						*(uint32 *)(Buf+4) *= 100;
						*(uint32 *)(Buf+4) += 99;
					}
					
					if( Byte2uInt(Buf) > *(uint32 *)(Buf+4) )
					{
						In->Result = DAR_OVERARRAY; //越界
						return k;
					}

					Hex2Bcd698Translate( Buf, Buf, 4 );                             //liruida  20241015
					
					Exchange( In->OutBuf+Offset, Buf+4-Len645, Len645 );
				}
			}
		}
		else
		{
			if( T_BIT_STRING == Type ) Len698 /= 8;
			
			if( (T_CSD == Type) && GetApduByte(In->RtBuf+k) ) //ROAD
			{
				Len645 += 5;
				Len698 += 5;
			}
		}
		
		k += Len698;
		In->RtBuf += k;
		In->OutBuf += Len645;
	}

	In->Type += 2;
	
	return k;
}


//数组内全为基本数据类型的格式化
unsigned int R_ARRAY( DRW_STRUCT *In )
//返回值：0=类型错; 1=越界; ≥2=正常
{
	unsigned char i;
	unsigned char Temp08;
	unsigned int k;
	unsigned long *BkPtr;
	
	BkPtr = In->Type;
	
	Temp08 = In->Type[1];
	if( In->Dir == 0 )
	{
		SendByte( In->Ch, In->Type[0] );
		
		if( T_ARRAY == In->Type[0] ) //针对元素可变的数组
		{
			i = In->Result;
			if( i && (Temp08 > i) ) Temp08 = i;
		}
		SendByte( In->Ch, Temp08 );
		
		In->OutBuf += 2;
	}
	else
	{
		if( In->Type[0] != GetApduByte(In->RtBuf+0) )
		{
			In->Result = DAR_DISMATCH; //类型不匹配
			return 0; 
		}

		i = GetApduByte(In->RtBuf+1);
		if( T_ARRAY == In->Type[0] )
		{
			if( i && (Temp08 > i) ) Temp08 = i;
		}
		
		if( i != Temp08 )
		{
			In->Result = DAR_OVERARRAY; //越界
			return 1;
		}
		
		In->RtBuf += 2;
	}

	k = 2;
	for( i=0; i<Temp08; i++ )
	{
		if( T_STRUCTURE == BkPtr[0] )
			In->Type = (uint32 *)(BkPtr[2+i]);
		else
			In->Type = (uint32 *)(BkPtr[2]);

		if( (T_ARRAY == In->Type[0]) || (T_STRUCTURE == In->Type[0]) )
		{
			k += R_ARRAY( In );
		}
		else//基础类型
		{
			k += R_NORMAL( In );
		}

		if( In->Result ) return k;
	}

	if( (T_STRUCTURE == BkPtr[0]) )
	{
		In->Type = BkPtr+2+i;
	}
	else
	{
		In->Type = BkPtr+3;
	}

	In->Result = 0; //成功
	return k;
}


//结构体和数组混合体的格式化
unsigned int R_STRUCTURE_ARRAY( DRW_STRUCT *In )
//返回值：0=类型错; 1=越界; ≥2=正常
{
	unsigned char i;
	unsigned int k=0, DoneBytes;
	unsigned long *Ptr;
	
//	In->Result = 0; //缺省结果为正常

	Ptr = In->Type; //数据格式末尾地址
	for( i=0; i<10; i++ )
	{
		if( *Ptr == 0 ) break;
		Ptr++;
	}
	
	do
	{
		if( (T_ARRAY == In->Type[0]) || (T_STRUCTURE == In->Type[0]) )
			DoneBytes = R_ARRAY( In );
		else//基础类型
			DoneBytes = R_NORMAL( In );
		
		k += DoneBytes;
		if( In->Result ) return k;
	} while( Ptr > In->Type );
	
	return k;
}


extern uint32 ProtocolSheet$$Base;
extern uint32 ProtocolSheet$$Limit;
unsigned long *Index2Type( unsigned long *const DtPtr, unsigned char Index )
{
	unsigned long *RtPtr;
	
	if(  (*(DtPtr+2)>=(uint32)&ProtocolSheet$$Base)&&(*(DtPtr+2)<(uint32)&ProtocolSheet$$Limit))
	{
		if( (0 == DtPtr[3]) || (0 == Index) )
			RtPtr = (uint32 *)(DtPtr[2]);
		else
			RtPtr = (uint32 *)(DtPtr[2+(Index-1)]);
	}
	else
	{
    
		if( (0xFF == *(((uint08 *)(DtPtr+2))+0)) || (0 == Index) ) //数据标识中最低字节为FF表示数据类型保持不变
			RtPtr = (uint32 *)(DtPtr[3+0]);
		else
			RtPtr = (uint32 *)(DtPtr[3+2*(Index-1)]);
	}
	
	return RtPtr;
}


unsigned char SearchMode( unsigned char *Oi, unsigned char *AckBuf )
{
	unsigned char i;
	
	for( i=0; i<safemodenum; i++ )
	{
		//if( (i%16) == 0 ) I2C_Read_Eeprom( ee_security_page1+(i/16), ee_security_inpage, AckBuf, ee_security_lenth );   liruida q  20240914
    
		if( (Byte2uShort(Oi) == Byte2uShort(AckBuf+(i%16)*4)) || (0xFFFF == Byte2uShort(AckBuf+(i%16)*4)) ) break;
	}

	return i;
}


//判断已存入APDU的数据+安全传输+跟随上报+时间标签+验证信息是否超出APDU最大尺寸
unsigned char CalApduLen( unsigned char Ch, unsigned short Total )
//返回值: 0=APDU未满; 1=APDU已满
{
	unsigned short Len=0;
	
	//跟随上报
	if( (0 == (Mode.Feature1&0x04)) || (Ch == CHHW) || (((0 == ModeEx.RptMode[8]) || (0 == Reportstatus[Ch])) && (0 == FollowReport[Ch])) ) //目前红外不支持跟随上报
	{
		Len += 1; //跟随上报信息
	}
	else if( ((Ch==CH485)&&((Mode.Feature1&0x30)==0x00)) || ((Ch==CHZB)&&((Mode.Feature1&0xc0)==0x00)) )//判断上报通道
	{
		Len += 1; //跟随上报信息
	}
	else
	{
		if( FollowReport[Ch] )
		{
			if( (0 == ModeEx.RptMode[8]) || (0 == Reportstatus[Ch]) ) Len += 9; //sizeof(ReportInf)
			else Len += 9; //sizeof(ReportInf2)
			Len += 4;
		}
		
		if( Reportstatus[Ch] && ModeEx.RptMode[8] )
		{
			if( 0 == FollowReport[Ch] ) Len += 10; //sizeof(ReportInf1);
			else Len += 7; //sizeof(ReportInf21); 
			Len += 4;
		}
	}
	
	//时间标签
	if( 0 == TimeTag[0] )  //时间标签
		Len += 1;
	else
		Len += 11;
		
	Total += Len;
	Len = 0;
	
	//安全传输
	if( Security_Mode == 0x01 ) //明文安全传输，请求：明文+RN，响应：明文+MAC
	{
		//10+00/01+长度
		if( Total < 0x80 )
			Len += 3;
		else if( Total < 0x100 )
			Len += 4;
		else
			Len += 5;
		
		Len += 7; //有验证信息+类型：MAC+MAC长度+MAC数据
	}
	
	if( (Security_Mode == 0x00) || //请求：明文+SID_MAC，应答：明文+MAC
	    (Security_Mode == 0x83) || //请求：密文+SID，应答：密文
	    (Security_Mode == 0x80) )  //请求：密文+SID_MAC，应答：密文+MAC
	{
		//加密应答帧
		if( Security_Mode == 0x00 ) //请求：明文+SID_MAC，应答：明文+MAC
		{
			Total = Total;
		}
		else if( Security_Mode == 0x83 ) //请求：密文+SID，应答：密文
		{
			Total = ((Total+2+16)/16)*16; //2字节是长度
		}
		else //请求：密文+SID_MAC，应答：密文+MAC
		{
			Total = ((Total+2+16)/16)*16; //2字节是长度
		}

		if( Total < 0x80 )
			Len += 3;
		else if( Total < 0x100 )
			Len += 4;
		else
			Len += 5;

		if( Security_Mode == 0x00 ) //请求：明文+SID_MAC，应答：明文+MAC
		{
			Len += 7; //有验证信息+类型：MAC+MAC长度+MAC数据
		}
		else if( Security_Mode == 0x83 ) //请求：密文+SID，应答：密文
		{
			Len += 1; //无验证信息
		}
		else //请求：密文+SID_MAC，应答：密文+MAC
		{
			Len += 7; //有验证信息+类型：MAC+MAC长度+MAC数据
		}
	}
	
	Total += Len;
	
	if( Total > MaxApduLen[Ch] ) return 1;
	else return 0;
}


unsigned short BaseTypeLen( unsigned char Type, unsigned char *Frame )
{
	uint16  n, Len=0, Loop=0;
	
	switch( Type )
	{
		//--- 固定长度 ---
//		case T_NULL					:  Len = 0; break;
		case T_BOOL	                :  Len = 1; break;  
		case T_DOUBLE_LONG	        :  Len = 4; break;  
		case T_DOUBLE_LONG_UNSIGNED :  Len = 4; break;  
		case T_INTEGER	            :  Len = 1; break;  
		case T_LONG	                :  Len = 2; break;  
		case T_UNSIGNED	            :  Len = 1; break;  
		case T_LONG_UNSIGNED	    :  Len = 2; break;  
		case T_LONG64	            :  Len = 8; break;  
		case T_LONG64_UNSIGNED	    :  Len = 8; break;  
		case T_ENUM	                :  Len = 1; break;  
		case T_FLOAT32	            :  Len = 4; break;  
		case T_FLOAT64	            :  Len = 8; break;  
		case T_DATE_TIME	        :  Len = 10; break;  
		case T_DATE	                :  Len = 5; break;  
		case T_TIME	                :  Len = 3; break;  
		case T_DATE_TIME_S          :  Len = 7; break;  
		case T_OI                   :  Len = 2; break;  
		case T_OAD	                :  Len = 4; break;  
		case T_OMD	                :  Len = 4; break;  
		case T_TI	                :  Len = 3; break;  
		case T_COMDCB	            :  Len = 5; break;  
		case T_SCALER_UNIT	        :  Len = 2; break;  
		
		//--- 可变长度 ---
		case T_RN:
		case T_MAC:
		case T_TSA:
		case T_UTF8_STRING:
		case T_OCTET_STRING:
		case T_VISIBLE_STRING:
			Len += GetDataLen( Frame, &Len );
			break;

		case T_BIT_STRING:
			if( (GetApduByte(Frame+0)&0x80) == 0 )
			{
				Len = (GetApduByte(Frame+0)+7)/8+1; //无长度域
			}
			else if( (GetApduByte(Frame+0)&0x7F) == 1 )
			{
				Len = (GetApduByte(Frame+1)+7)/8+2; //长度字节
			}
			else 
			{
				CopyApdu( (uint08*)(&Len), Frame+1, 2 );
				Inverse((uint08*)(&Len),2);
				Len = (Len+7)/8+3; //长度字节
			}
			break;

		//--- 可变字节 ---
		case T_SID: 
			Len += 4;
			Len += GetDataLen(Frame+Len, &Len); 
			break;
			
		case T_ROAD:
			Len += 4;
			Len += 4*GetDataLen(Frame+Len, &Len); 
			break;
			
		case T_SID_MAC: //5E 81 1C 33 10 02 00 14 04 21 47 EF 58 
			Len += 4;
			Len += GetDataLen(Frame+Len, &Len);
			Len += GetDataLen(Frame+Len, &Len); 
			break;
		
		case T_CSD:
			if( 00 == GetApduByte(Frame+Len) ) //OAD
			{
				Len += 5;
			}
			else //ROAD
			{
				Len += 5;
				Len += 4*GetDataLen(Frame+Len, &Len);
			}
			break;

		case T_RCSD:
			Loop = GetDataLen( Frame, &Len );
			for( n=0; n<Loop; n++ )
			{
				if( 0 == GetApduByte(Frame+Len) )
				{
					Len += 5;
				}
				else
				{
					Len += 5;
					Len += 4*GetDataLen(Frame+Len, &Len);
				}
			}
			break;

		default:  Len = 0; break;
	}

	return Len;
}

extern unsigned short Type2Len( unsigned char Type, unsigned char *Frame, unsigned char *Depth );




//Region类型数据的长度
unsigned short RegionLen( unsigned char Type, unsigned char *Frame, unsigned char *Depth )
{
	unsigned short Len = 0;
	unsigned char InitDepth;

	InitDepth = *Depth;

	Len += 1; //单位  ENUMERATED
	
	*Depth = InitDepth;
	Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //起始值 Data
	if( *Depth == 0 ) return 0;

	*Depth = InitDepth;
	Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //结束值 Data
	if( *Depth == 0 ) return 0;

	return Len;
}


//MS类型数据的长度
unsigned short MSLen( unsigned char Type, unsigned char *Frame, unsigned char *Depth )
{
	unsigned short i, Len=0, Loop=0;
	unsigned char InitDepth;

	InitDepth = *Depth;
	
	Len += 1; //CHOICE
	switch( Frame[0] ) //MS∷=CHOICE
	{
		case 0: //无电能表		[0]，
		case 1: //全部用户地址  	[1]，
			break;
					
		case 2: //一组用户类型  	[2] 	SEQUENCE OF unsigned，
			Len += GetDataLen( Frame+Len, &Len );
			break;
					
		case 3: //一组用户地址  	[3] 	SEQUENCE OF TSA，
			Loop = GetDataLen( Frame+Len, &Len );
			for( i=0; i<Loop; i++ )
			{
				Len += BaseTypeLen( T_TSA, Frame+Len );
			}
			break;
					
		case 4: //一组配置序号  	[4] 	SEQUENCE OF long-unsigned，
			Len += 2*GetDataLen( Frame+Len, &Len );
			break;
					
		case 5: //一组用户类型区间 [5] SEQUENCE OF Region，
		case 6: //一组用户地址区间 [6] SEQUENCE OF Region，
		case 7: //一组配置序号区间 [7] SEQUENCE OF Region
			Loop = GetDataLen( Frame+Len, &Len );
			for( i=0; i<Loop; i++ )
			{
				*Depth = InitDepth;
				Len += RegionLen( T_REGION, Frame+Len, Depth );
				if( *Depth == 0 ) return 0;
			}
			break;
					
		default:
			break;
	}
	
	return Len;
}

unsigned short RsdLen( unsigned char Type, unsigned char *Frame, unsigned char *Depth )
{
	unsigned short i, Len=0, Loop=0;
	unsigned char InitDepth;

	InitDepth = *Depth;

	Len += 1; //RSD∷=CHOICE
	switch( GetApduByte(Frame+0) ) //RSD∷=CHOICE
	{
		case 0: //不选择    [0]  NULL
			Len += 0;
			break;
			
		case 1: //选择方法1 [1]  Selector1
			Len += 4;
			*Depth = InitDepth;
			Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1;
			if( *Depth == 0 ) return 0;
			break;
			
		case 2: //选择方法2  	 [2]  Selector2
			Len += 4;	//OAD
			*Depth = InitDepth;
			Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //起始值 Data
			if( *Depth == 0 ) return 0;

			*Depth = InitDepth;
			Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //结束值 Data
			if( *Depth == 0 ) return 0;

			*Depth = InitDepth;
			Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //数据间隔 Data
			if( *Depth == 0 ) return 0;
			break;
			
		case 3:	//Selector3∷=SEQUENCE OF Selector2
			Loop = GetDataLen( Frame+Len, &Len );
			for( i=0; i<Loop; i++ )
			{
				Len += 4;	//OAD
						
				*Depth = InitDepth;
				Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //起始值 Data
				if( *Depth == 0 ) return 0;
	
				*Depth = InitDepth;
				Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //结束值 Data
				if( *Depth == 0 ) return 0;
	
				*Depth = InitDepth;
				Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1; //数据间隔 Data
				if( *Depth == 0 ) return 0;
			}
			break;
			
		case 4: //Selector4∷=SEQUENC
			Len += BaseTypeLen( T_DATE_TIME_S, Frame+Len ); //采集存储时间  date_time_s

			*Depth = InitDepth;
			Len += MSLen( T_MS, Frame+Len, Depth ); //电能表集合          MS
			if( *Depth == 0 ) return 0;
			break;
			
		case 5: //Selector5∷=SEQUENC
			Len += BaseTypeLen( T_DATE_TIME_S, Frame+Len ); //采集存储时间  date_time_s

			*Depth = InitDepth;
			Len += MSLen( T_MS, Frame+Len, Depth ); //电能表集合          MS
			if( *Depth == 0 ) return 0;
			break;
			
		case 6: //Selector6∷=SEQUENCE
		case 7: //Selector7∷=SEQUENCE
		case 8: //Selector8∷=SEQUENCE
			Len += BaseTypeLen( T_DATE_TIME_S, Frame+Len ); //采集启动时间起始值  date_time_s
			Len += BaseTypeLen( T_DATE_TIME_S, Frame+Len ); //采集启动时间结束值  date_time_s
			Len += BaseTypeLen( T_TI, Frame+Len );  //时间间隔            TI
			*Depth = InitDepth;
			Len += MSLen( T_MS, Frame+Len, Depth ); //电能表集合          MS
			if( *Depth == 0 ) return 0;
			break;
			
		case 9: //选择方法9  	 [9]  Selector9
			Len += 1;
			break;
			
		case 10: //Selector10∷=SEQUENCE
			Len += 1;
			*Depth = InitDepth;
			Len += MSLen( T_MS, Frame+Len, Depth ); //电能表集合          MS
			if( *Depth == 0 ) return 0;
			break;
			
		default:
			break;
	}
	
	return Len;
}


//统计指定数据类型的数据的字节长度
unsigned short Type2Len( unsigned char Type, unsigned char *Frame, unsigned char *Depth )
{
	unsigned short i, Len=0, Loop=0;
	unsigned char InitDepth;
	
	if( *Depth ) (*Depth)--;
	else return Len;

	InitDepth = *Depth;
	switch( Type )
	{
		case T_ARRAY:
		case T_STRUCTURE:
			Loop = GetDataLen( Frame, &Len );
			for( i=0; i<Loop; i++ )
			{
				if( (T_ARRAY == GetApduByte(Frame+Len)) || (T_STRUCTURE == GetApduByte(Frame+Len)) )
				{
					*Depth = InitDepth;
					Len += Type2Len( GetApduByte(Frame+Len), Frame+1+Len, Depth )+1;
					if( *Depth == 0 ) return 0;
				}
				else
				{
					Len += BaseTypeLen( GetApduByte(Frame+Len), Frame+1+Len )+1;
				}
			}
			break;
			
		case T_RSD:
			*Depth = InitDepth;
			Len = RsdLen( Type, Frame, Depth );
			if( *Depth == 0 ) return 0;
			break;

		case T_REGION:  //0x58
			*Depth = InitDepth;
			Len = RegionLen( Type, Frame, Depth );
			if( *Depth == 0 ) return 0;
			break;
			
		case T_MS:
			*Depth = InitDepth;
			Len = MSLen( Type, Frame, Depth );
			if( *Depth == 0 ) return 0;
			break;

		default: 
			Len = BaseTypeLen( Type, Frame );
			break;
	}
	
	return Len;
}


//高字节在前的数据比较
unsigned char Cmp_Data( unsigned char *BufA, unsigned char *BufB, unsigned short Len )
{
	unsigned short i;

	for( i=0; i<Len; i++ )
	{
		if( BufA[i] > BufB[i] )
		{
			return 1; //A>B
		}
		else
		{
			if( BufA[i] < BufB[i] )
			{
				return 2; //A<B
			}
		}
	}

	return 3; //A=B
}

const uint08 code MaxDays []={0x31,0x28,0x31,0x30,0x31,0x30,0x31,0x31,0x30,0x31,0x30,0x31};

uint08 Judge_Clock( uint08 Start, uint08 *Ck, uint08 Len )//周在中间
{
	unsigned char  i, j, k=0;
	const uint08 code Max[]={ 0x59,0x59,0x23,0x6,0x31,0x12,0x99 }, code Min[]={ 0x00,0x00,0x00,0x00,0x01,0x01,0x00 };

	if( (Len&0x80) == 0 ) k = 1;	//有周
		
	for( i=0; i<(Len&0x07f); i++ )
	{
		j=i+Start;
		if((j>=3)&&(Len&0x80))	j++;
		
		if( (Ck[i] > Max[j]) || (Ck[i] < Min[j]) ) return 1;//合法性检查错误
		if( IsBCD(Ck[i]) ) return 1;	//BCD码检查错误		  
		
		if( (j == 4) && ((Start+(Len&0x07f)) > (4+k)) ) //Day
		{
			if( (Ck[i+1] == 0x02) && ((Start+(Len&0x07f)) > (5+k)) ) //Month
			{
				if( (Bcd_To_Hex(Ck[i+2])&0x03) == 0 ) //闰年Year
				{
					if( Ck[i] > 0x29 ) return 1;
				}
				else
				{
					if( Ck[i] > 0x28 ) return 1;
				}
			}
			else
			{
				if( Ck[i] > MaxDays[Bcd_To_Hex(Ck[i+1])-1] ) return 1;
			}
		}
	}
	return 0;//正确
}


unsigned char JudgeClockNoWeek( uint08 Start, uint08 *Ck, uint08 Len )
{
	return(Judge_Clock( Start, Ck, Len+0x80 ));
}

unsigned char Cal_Comb_0000( unsigned char DI2, unsigned char DI1, unsigned char DI0, unsigned char *ReturnBuf )  //wujiafei
{
	unsigned char i, k, n, result, Temp08, ptrmax;
	unsigned char Buf[ee_histroydl_lenth];
	union B32_B08 Temp32;
	
//------------------------------------------wujiafei  20241021------------------------------------------------
    int data = 0; 
	unsigned char ucOpt;  //组合有功电能
	unsigned int eRateType;  //电能量费率类型
	float pdValue=0;     //读取到的有功电量	
	union B32_B08_2 buff_wjf;   // 读取到的有功电量转化为4字节，便于存储
	k=4;
	if((0!=DI2)||(0!=DI2))
	{
		return 2;
	}
	if(0==DI2) //特征字类型
	{
		ucOpt = pstParm->Word.CharWord.CombinedAaactive;   //组合有功特征字
	}
	
	switch(ReturnBuf[4])  //电能量费率类型，对应OAD中的索引
	{
		case 0x00:  //块
			//eRateType=4;
		    //break;
		case 0x01:
			eRateType=4;
		    break;
		case 0x02:
		case 0x03:
		case 0x04:
		case 0x05:
			eRateType=ReturnBuf[4]-2;
		    break;
		default:
			return 2;
			break;
	}
	if ((ucOpt & PARM_COMB_ACT_ENERGY_STATUS_POS_ADD) == PARM_COMB_ACT_ENERGY_STATUS_POS_ADD)
	{
		pdValue += stDataColl.stDataABC.dEnergyPos[eRateType][AC_ENERGY_EPT]; 
	}
	if ((ucOpt & PARM_COMB_ACT_ENERGY_STATUS_POS_SUB) == PARM_COMB_ACT_ENERGY_STATUS_POS_SUB)
	{
		pdValue -= stDataColl.stDataABC.dEnergyPos[eRateType][AC_ENERGY_EPT];
	}
	if ((ucOpt & PARM_COMB_ACT_ENERGY_STATUS_NEG_ADD) == PARM_COMB_ACT_ENERGY_STATUS_NEG_ADD)
	{
		pdValue += stDataColl.stDataABC.dEnergyNeg[eRateType][AC_ENERGY_EPT];
	}
	if ((ucOpt & PARM_COMB_ACT_ENERGY_STATUS_NEG_SUB) == PARM_COMB_ACT_ENERGY_STATUS_NEG_SUB)
	{
		pdValue -= stDataColl.stDataABC.dEnergyNeg[eRateType][AC_ENERGY_EPT];
	}
	data = (int)(pdValue * 100);
	Int2Byte(data,buff_wjf.B08);
	for (int i = 0; i < 4; ++i)
	{
        ReturnBuf[1+i]=buff_wjf.B08[i];						

	}

	return (k);
}

RetFrame FrameProc( unsigned char Ch, unsigned char *OutBuf )
{
	unsigned char i, k, n=0, Temp08=0, result, Err_DI=0, Auth=0;
	unsigned int  MeterClear = 0;
	unsigned char Buf[64];
	unsigned char ecode *Code_Flash_Char;
//	unsigned char *Ptr;
	union B16_B08_2 Temp16;
	union B32_B08_2 Temp32,DI07;
	union B32_B08_2 OptID;
	RetFrame Ret = {0,0,0,0};
		
	//Clear_Wdt();  liruida 20240929 	
	Ret.AckLen = 0;
	Ret.Value = 0;

	k = 0x00;
	OutBuf[0] = 0x00;
	
	memcpy( DI07.B08, Uart[Ch].Buf+10 ,4 );
	memcpy( OptID.B08, Uart[Ch].Buf+14 ,4 );
	
	switch( Uart[Ch].Buf[8] ) //cmd
	{
		
		#ifdef CASE_READ
		case 0x11:	//读取
		
			if( Uart[Ch].Flag&B0000_0001 ) break; //通讯地址全99   不支持
			
			switch( DI07.B08[3] )
			{
				case 0x00: //wujiafei 读组合有功 
						k=Cal_Comb_0000(DI07.B08[2],DI07.B08[1],DI07.B08[0],OutBuf); 
						if(2==k)     //错误,返回拒绝读写
						{
							OutBuf[0] = 0xFF;	//Operation result.
						    OutBuf[1] = 0x02;	//数据标识错, 无请求数据
						}
					break;							
				case 0x02:	//变量数据标识
					if( DI07.B08[2] == 0x80 )
					{
					
					}
					else
					{
						if( DI07.B08[0] != 0x00 ) break;
						
						Temp08 = 0x00;
						switch( DI07.B08[2] )
						{
							case 0x01:	//A相电压	XXX.X	2
							//case 0x02:	//A相电流	XXX.XXX	3
								if( (DI07.B08[1] == 0x01) || (DI07.B08[1] == 0xFF) )
								{
									if( DI07.B08[2] == 0x01 ) Temp08 = 2;
									else Temp08 = 3;
								}
								break;
								
							default:
								break;
						}
						
						if( Temp08 )
						{
							float pdValue = 0;                                                    //liruida 20241009
							pdValue = stDataColl.stDataABC.dVoltage[AC_VOLTAGE_A];                //平均值模式下电压值  liruida 20241009
							int data = 0;
							data = (int)(pdValue * 10);
							for (int i = 0; i < 2; ++i)
							{
								OutBuf[1+i] = DEC2BCD(data % 100); data /= 100;

							}
							
							
							if( dl_back_flag && (
							(DI07.B08[2]==0x02) ||
							(DI07.B08[2]==0x03) ||
							(DI07.B08[2]==0x06) ) )	OutBuf[Temp08] |= 0x80;
							
							k = 1+(Temp08);
							if( DI07.B08[1] == 0xFF )
							{
								if(DI07.B08[2] >= 0x03 )
								{
									memcpy( OutBuf+k, OutBuf+1, (Temp08) );
									k += Temp08;
								}

								memset( OutBuf+k, 0xFF, 2*(Temp08) );
								k += 2*(Temp08);
							}
						}
					}
					break;
				
								
				case 0x04:	//参变量数据标识
					switch( DI07.B08[2] )
					{
						case 0x00:
							switch( DI07.B08[1] ) 
							{
								case 0x04:	  
									switch( DI07.B08[0] )
									{
										case 0x01:	//通信地址                     	NNNNNNNNNNNN	6
											k = 7;
											memcpy(Comm_Addr.Comm_Id, pstParm->Terminal.Struct.TermInfo.Struct.TermAddr, 6);
											Exchange( OutBuf+1, Comm_Addr.Comm_Id, 6 );
											break;
										
										case 0x02:	//表号                         	NNNNNNNNNNNN	6
											memcpy( Esam_Para.Meter_Id, pstParm->Terminal.Struct.TermInfo.Struct.TermSnum, 8 );//复制esam表号到ram
											Exchange( OutBuf+1, Esam_Para.Meter_Id+2, 6 );
											k = 7;
											break;
											
											
										default:	break;
									}
									break;

								default:
									break;
							}
							break;
							
						default: break;
					}
					
				default: break;
			}
			break;
		
			
		#endif
		
		//====================================================================================
		#ifdef CASE_WRITE
		case 0x14: //写参变量
			if( Uart[Ch].Buf[9] <= 12 ) break;//数据长度必须大于12

			memcpy( OptID.B08, Uart[Ch].Buf+18 ,4 );

			Auth = Uart[Ch].Buf[14];
			switch( Auth ) //密码权限
			{
				case 0x02:	//厂内扩展命令
					switch( DI07.B08[2] )
					{
						case 0x00:
							switch( DI07.B08[1] )
							{
								case 0x04:	  
									switch( DI07.B08[0] )
									{
										case 0x01:	//通信地址                     	NNNNNNNNNNNN	6
											memset( Buf, 0x99, 6 );
											if( Cmp_Data( Buf, Uart[Ch].Buf+22, 6 ) ==3 ) break;	//禁止设置全9
											if( IsMultiBcd( Uart[Ch].Buf+22, 6 ) )	break;
											
											Exchange( Buf, Uart[Ch].Buf+22, 6 );
																						
											//result = WriteE2WithBackup( ee_commaddr_page, ee_commaddr_inpage, Buf, ee_commaddr_lenth ); liruida q 20241010
											result = ParmSet_TermAddr(Buf);
											if( result != 0x00 ) break;
												
											memcpy( Comm_Addr.Comm_Id, Buf, 8 );
	
											k = 1;
											break;										

										default:
											Err_DI = 1;	//数据标识错
											break; 

									}
									break;								
								default:
									Err_DI = 1;	//数据标识错
									break;							
							}
							break;
							
						default:
							Err_DI = 1;	//数据标识错
							break;						

					}
					break;

				default:
					Err_DI = 1;	//Error: bit2密码错误/未授权
					break;
			}

			if( Err_DI )	//用户对不支持写操作的数据项编程，返回异常应答帧，将错误信息字Bit2置1，即“密码错/未授权”。
			{
				k = 2;
				OutBuf[0] = 0xFF;	//Operation result.
				OutBuf[1] = 0x04;	//Error: bit2密码错误/未授权
				break;
			}
						
			if( k && (OutBuf[0] == 0x00) )
			{
				if( !(Uart[Ch].Flag&B0100_0000) ) //645通道
				{
					//ProgramRecord( DI07.B08, OptID.B08 );  liruida q 20241010
				}
			}
			break;

		
		#endif
		
		
		default:
			k = 2;
			OutBuf[0] = 0xFF;	//Operation result.
			if( Uart[Ch].Buf[8]&0x40 )	//红外通信口
			{
				if( (Uart[Ch].Buf[8]&0x3F) == 0x03 )
				{
					OutBuf[1] = 0x01;
					OutBuf[2] = 0x00;
					k++;
				}
				else
				{
					OutBuf[1] = 0x04; 	//Error: bit4密码错误/未授权
				}
			}
			else
				OutBuf[1] = 0x02;	//数据标识错, 无请求数据
			break;


		

									
	}
	
	Ret.AckLen = k;
	Ret.Value = MeterClear;
	
	return Ret;
	
	
}



extern unsigned char Judge_HwAuth( unsigned char Ch, unsigned char Type, unsigned char *Oi );

///*判断安全模式
//	Type: 		操作类型：读(5)，写(6)，操作(7)
//	Oi:				操作OI
//	Oisn：		OI在MapTab表中的偏移量

//	写/操作命令支持的安全模式:
//	明文：				明文、明文SIDMAC、密文SID、密文SIDMAC
//	明文+验证码：	明文SIDMAC、密文SID、密文SIDMAC
//	密文：				密文SID、密文SIDMAC
//	密文+验证码：	密文SIDMAC
//	
//	读命令支持的安全模式：
//	明文：				明文、明文RN、明文SIDMAC、密文SID、密文SIDMAC
//	明文+验证码：	明文RN、明文SIDMAC、密文SID、密文SIDMAC
//	密文：				密文SID、密文SIDMAC
//	密文+验证码：	密文SIDMAC
//*/
unsigned char Security_Judge( unsigned char Ch, unsigned char Type, unsigned char *Oi, unsigned char *Oisn )
{
	unsigned char i, result;
	unsigned int TypeTemp;
	unsigned char Buf[64];
//	RetFrame Ret = {0,0,0,0};
	
	//取得通信命令的安全模式：安全传输 or 通用传输
	//取得目标对象的安全模式
	result = FindOI( Oi );
	if( result == 0xFF ) return DAR_UNEXISTED;
	*Oisn = result;


	return 0;
}


//红外认证不通过或红外认证失效后，
//电能表应仅支持读表号、通信地址、备案号、当前日期、当前时间、
//当前电能、当前剩余金额、
//红外认证查询命令，其它信息不允许读出，所有信息均不允许设置
//Type=GET_REQUEST 抄读；Type=SET_REQUEST 设置；Type=ACTION_REQUEST 操作
unsigned char Judge_HwAuth( unsigned char Ch, unsigned char Type, unsigned char *Oi )
{
	unsigned char Temp08, AuthPass;

	//if( Progkey.Timer || xj_factory_flag ) return 0;   liruida q 20240914

	Temp08 = 0xFF;	//默认不允许抄读
	if( Type == GET_REQUEST )	//读命令
	{
		switch( Byte2uShort(Oi) )
		{
			case 0x0000:	//组合电量
			case 0x0010:	//正向电量
			case 0x0020:	//反向电量
			case 0x4002:	//表号
			case 0x4001:	//通信地址
			case 0x4111:	//备案号
			case 0x4000:	//当前日期
			case 0x2031:	//当前月用电量	
			#if( METERTYPE == 0x00 )//本地费控电能表
			case 0x2032:	//当前年用电量
			case 0x202c:	//剩余金额
			case 0x202d:	//透支金额
			#endif	
				Temp08 = 0x00;
				break;
				
			case 0xF100:	//Esam
			case 0xF101:	//安全模式参数
				if( CHHW != Ch ) Temp08 = 0x00; 
				break;
				
			default:
				break;
		}
	}
	else if( Type == ACTION_REQUEST )
	{
		switch( Byte2uInt(Oi) )
		{
			case 0x80008300: //明文拉合闸
			case 0xF1000B00: //红外认证请求
			case 0xF1000C00: //红外认证
				Temp08 = 0x00;
				break;
				
			default: 
				break;
		}
	}
	
	AuthPass = 0;
//	if( CHHW == Ch ) //红外通道    liruida q20240914
//	{
//		if( 0 == Uart[Ch].Client ) return DAR_REFUSERW; //终端不支持红外通道
//		if( Temp08 
//		&& (0 == IR_EnTimer) 
//		&& (0 == Progkey.Timer) && (0==xj_factory_flag) ) return DAR_REFUSERW;	//厂内无需红外认证, 厂外拒绝读写
//	}
	
	//不区分物理通道
	if( (2 == ConectType[Uart[Ch].Client][CHHW ]) 
	 || (2 == ConectType[Uart[Ch].Client][CH485]) 
	 || (2 == ConectType[Uart[Ch].Client][CHZB ]) )
		AuthPass |= 1;  //已建立对称会话

	if( (0 == Uart[Ch].Client) && Term_EnTimer )
		AuthPass |= 2; //终端的身份认证通过
	
	if( (0xFF == Security_Mode)   //明文
	 || (0x01 == Security_Mode) ) //明文+RN
	{
		if( Ch //RS485 or 载波
		&& (0 == esam_error)  //Esam正常
		&& Esam_Para.AuthOn ) //身份认证权限启用
		{
			if( Temp08 
			&& (Type == GET_REQUEST)
			&& (0 == AuthPass) ) return DAR_REFUSERW;	//拒绝读写
		}
	}
	else 
	if( (0x00 == Security_Mode ) //明文+SID_MAC
	||  (0x83 == Security_Mode ) //密文+SID
	||  (0x80 == Security_Mode)) //密文+SID_MAC
	{
		if( (0x30 != (Uart[Ch].Flag&0x30)) //非广播地址
		&&  (0x00 == (AuthPass&1)) ) //对称会话失效
			return DAR_REFUSERW; //拒绝读写
	}
	
	return 0;
}


//过流记录
void OverCurrChg( unsigned char *Frame, unsigned char Dir )
{
	unsigned char Temp08;
	const unsigned char code OverCur[2][12] = { 
		{ 0, 1, 3, 4, 5, 6,10, 2,11, 9, 7, 8 },
		{ 0, 1, 7, 2, 3, 4, 5,10,11, 9, 6, 8 } };

	if( (0x30 != GetApduByte(Frame)) || (0x05 != GetApduByte(Frame+1)) ) return; //只有过流事件才进行属性转换
	
	Temp08 = GetApduByte(Frame+2);
	if( Temp08 < 12 ) PutApduByte( Frame+2, OverCur[Dir&1][Temp08] );
			
}



RetFrame GetNormal( uint08 Ch, unsigned char *Frame )
{
	unsigned char i, j, n, m, Temp08, BkValue;
	union B16_B08 Temp16;
	unsigned int DoneBytes;
	unsigned char Oi[8];
	unsigned char *RtBuf = Uart[Ch].Buf+16;
	unsigned int k;
	DRW_STRUCT RtPtr;
	unsigned long *DtPtr;
	AttrMethod *AMptr;
	RetFrame Ret = {0,0,0,0};
	RetFrame ComRet = {0,0,0,0};

	k = Uart[Ch].Total698;

	CopyApdu( Oi, Frame, 8 );
	
	Ret.DoneLen += 4; //已处理: OAD
	
	if( (0x30 == Oi[0]) || (0x50 == Oi[0]) )
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}
	
	Ret.DAR = Security_Judge( Ch, GET_REQUEST, Oi, &Temp08 );//查找oi及判断安全模式  // liruida q
	if( Ret.DAR ) return Ret; //liruida q 20240919
	
	Ret.DAR = DAR_UNEXISTED; //对象不存在

	//确认支持的属性
	AMptr = (AttrMethod *)(MapTab[Temp08].DtType);
	
	i = 0xFF;
	for( n=0; n<20; n++ ) //统计支持的所有属性个数
	{
		if( 0xFF == AMptr[n].Sn ) break;
		if( (0 == Oi[2]) || (Oi[2] == (AMptr[n].Sn&0x3F)) ) 
		{
			if( 0 == (AMptr[n].Sn&0x80) ) 
			{
				if( Oi[2] )
				{
					Ret.DAR = DAR_REFUSERW; //拒绝读写
					return Ret;
				}
				else
				{
					break; //遇到某属性不支持读取，则退出
				}
			}

			i = n;  //在所属类中找到属性编号
		}
	}
	
	if( Oi[2] == 0 )	//不支持属性0
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}
	
	if( (Byte2uShort(Oi) == 0x4300) && (Oi[2] == 10) && Oi[3] )	//只允许索引为0读取电气设置的上报通道
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}

	if( Oi[2] < 2 )
	{
		if( Oi[3] ) return Ret; //对象不存在
		i = 0x01;
	}
	else
	{
		if( i == 0xFF ) return Ret; //对象不存在
		i += 2;
	}
	
	for( ; i<n+2; i++ )  //属性标识及其特征
	{
		BkValue = Ret.Value;
		
		if( i == 1 ) //1．逻辑名
		{
			if( k == Uart[Ch].Total698 ) SendByte( Ch, 0x01 ); //CHOICE = Data
			
//			if( 0 == Oi[2] ) //全部属性
//			{
//				SendByte( Ch, T_STRUCTURE  );
//				SendByte( Ch, n+1  );
//			}
			
			SendByte( Ch, T_OCTET_STRING );
			SendByte( Ch, 0x02  );
			SendByte( Ch, Oi[0] );
			SendByte( Ch, Oi[1] );
		}
		else
		{
			DtPtr = (uint32 *)(AMptr[i-2].Addr); //指向具体的属性数据类型列表
			if( T_SCALER_UNIT == DtPtr[0] ) //换算及单位
			{
				if( Oi[3] ) return Ret; //对象不存在
				
				if( k == Uart[Ch].Total698 ) SendByte( Ch, 0x01 );

				SendByte( Ch, DtPtr[0] );
				SendByte( Ch, *(((uint08 *)(DtPtr+1))+1) );
				SendByte( Ch, *(((uint08 *)(DtPtr+1))+2) );
			}
			else
			{
				Temp08 = 0;
				if( (T_ARRAY == DtPtr[0]) || (T_STRUCTURE == DtPtr[0]) )
				{
					if( Oi[3] > DtPtr[1] ) //元素索引不能大于元素总个数
					{
						Ret.DAR = DAR_UNEXISTED; //对象不存在
						return Ret;
					}
					
					if( Oi[3] ) //元素索引：0全部, 1~n单个元素
					{
						Temp16.B08[0] = Oi[3]-1;
						Temp16.B08[1] = Oi[3];
					}
					else
					{
						Temp16.B08[0] = Uart[Ch].EleSn;
						Temp16.B08[1] = DtPtr[1];

						if( (Byte2Int(Oi) == 0x00000200) || (Byte2Int(Oi) == 0x00100200) || (Byte2Int(Oi) == 0x00200200) || 
							(Byte2Int(Oi) == 0x00000400) || (Byte2Int(Oi) == 0x00100400) || (Byte2Int(Oi) == 0x00200400) ||
							(Byte2Int(Oi) == 0x00000600) || (Byte2Int(Oi) == 0x00100600) || (Byte2Int(Oi) == 0x00200600) )//当前组合、正向和反向电量，高精度，尾数
						{
							Temp16.B08[1] = Bcd_To_Hex(Feik.Num[3])+1; //总和费率数
						}
						
						if( (0x048100FF == DtPtr[2]) || (0x048200FF == DtPtr[2]) ) //当前套时区表 or 备用套时区段表
						{
//							Temp08 = 1;
							Temp16.B08[1] = Bcd_To_Hex(Feik.Num[0]); //时区数
						}
						else if( (0x040100FF == DtPtr[2]) || (0x040200FF == DtPtr[2]) ) //当前套日时段表 or 备用套日时段表
						{
							Temp08 = 1; //每次读取一个日时段表, 禁止关联对象的索引为0进行冻结
							Temp16.B08[1] = Bcd_To_Hex(Feik.Num[1]); //日时段表数
						}
						else if( (0x040501FF == DtPtr[2]) || (0x040502FF == DtPtr[2]) ) //当前套费率电价 or 备用套费率电价
						{
//							Temp08 = 1;
							Temp16.B08[1] = Bcd_To_Hex(Feik.Num[3]); //费率数
						}
						else if( 0x040300FF == DtPtr[2] ) //公共假日表
						{
//							Temp08 = 1;
							Temp16.B08[1] = Bcd_To_Hex(Feik.Num[4]); //公共假日数
						}
						// else if( (0x040403FF == DtPtr[2]) || (0x040404FF == DtPtr[2]) ) //自动轮显 or 按键轮显   //liruida q
						// {
						// 	Temp08 = 2; //每次读取一个，支持关联对象的索引为0进行冻结
						// 	if( 0x040403FF == DtPtr[2] ) //自动轮显
						// 		Temp16.B08[1] = Display_Para.S_Number; //循显屏数
						// 	else //按键轮显
						// 		Temp16.B08[1] = Display_Para.K_Number; //键显屏数
						// }

						if( (T_ARRAY == DtPtr[0]) && (0 == Temp16.B08[1]) ) //数组内元素为0，返回NULL
						{
							if( k == Uart[Ch].Total698 ) SendByte( Ch, 0x01 ); //CHOICE = 数据
							SendByte( Ch, T_ARRAY ); //数据类型
							SendByte( Ch, 0 ); //NULL
						}
					}
				}
				else
				{
					if( Oi[3] )
					{
						Ret.DAR = DAR_UNEXISTED; //对象不存在
						return Ret;
					}
					
					Temp16.B08[0] = 0;
					Temp16.B08[1] = 1;
				}


				{
					//读取数据
					for( j=Temp16.B08[0]; j<Temp16.B08[1]; j++ ) //属性内元素个数
					{

						{
							Uart[Ch].Buf[8] = 0x11;
							Uart[Ch].Buf[9] = 0x04;
							if( 0xFF == *(((uint08 *)(DtPtr+2))+0) ) //数据标识中最低字节为FF表示需从01开始读取
							{
								memcpy( Uart[Ch].Buf+10, (uint08 *)(DtPtr+2), 4 );
								Uart[Ch].Buf[10] = j+1;
							}
							else
							{
								memcpy( Uart[Ch].Buf+10, (uint08 *)(DtPtr+2+2*j), 4 ); //
							}
							ComRet = FrameProc( Ch, RtBuf+Ret.Value ); //命令执行
							if( (ComRet.AckLen == 0) || (RtBuf[Ret.Value] != 0x00) )
							{
								if( ComRet.DAR == 0 )
									ComRet.DAR = DAR_REFUSERW; //拒绝读写
								Ret.DAR = ComRet.DAR;
							}
							
							if( ComRet.DAR )
							{
								if( T_ARRAY != DtPtr[0] )  return Ret;
								else if( Oi[3] ) return Ret;
							}
							
							RtBuf[ Ret.Value ] = ComRet.AckLen; //方便补充冻结取数
						}
						
						if( ((j+1) == Temp16.B08[1]) || ComRet.DAR || Temp08 ) //读完所有元素 or 读取失败 or 特殊处理
						{
							//组响应帧
							if( k == Uart[Ch].Total698 ) SendByte( Ch, 0x01 ); //CHOICE = 数据
							
							if( (0 == Temp08) || (j == Temp16.B08[0]) )
							{
								if( (T_ARRAY == DtPtr[0]) && ComRet.DAR ) 
								{
									if( j )
									{
										Temp16.B08[1] = j;
									}
									else
									{
										SendByte( Ch, T_ARRAY ); //数据类型
										SendByte( Ch, 0 ); //NULL
										break;
									}
								}
								
								if( (0 == Oi[3]) && ((T_ARRAY == DtPtr[0]) || (T_STRUCTURE == DtPtr[0])) )
								{
									SendByte( Ch, DtPtr[0] ); //数据类型
									SendByte( Ch, Temp16.B08[1] ); //元素个数
								}
							}
	
							RtPtr.Ch = Ch;
							RtPtr.Dir = 0;
							RtPtr.RtBuf = RtBuf+BkValue;
							
							for( m=Temp16.B08[0]; m<Temp16.B08[1]; m++ ) //属性内元素个数
							{
								uint16 curOI;
								uint32 curOAD;
								
								curOI = Byte2uShort(Oi);
								curOAD = Byte2Int(Oi);
								//组帧
								RtPtr.Result = 0;
//								if( CountFlag == 0 ) 
								{
									if( (0x4016 == curOI) || (0x4017 == curOI) ) //特殊处理可变数组
									{
										RtPtr.Result = (ComRet.AckLen-1)/3;
									}
									
									if( 0x33200200 == curOAD ) //新增事件列表，只读
									{
										RtPtr.Result = (ComRet.AckLen-1)/4;
									}
									
									if( 0x33200300 == curOAD ) //需上报事件对象列表，只读
									{
										RtPtr.Result = (ComRet.AckLen-1)/2;
									}
								}
//								else
//								{
//									if( (0 == Oi[3]) && (T_ARRAY == DtPtr[0]) ) 
//									{
//										RtPtr.Result = Oi[5]; //数组中元素的个数
//									}
//								}
	
								RtPtr.Type = Index2Type( DtPtr, (m+1) );
								RtPtr.RtBuf += 1;
								DoneBytes = R_STRUCTURE_ARRAY( &RtPtr ); 
//								Ret.DoneLen += DoneBytes;
	
								if( Uart[Ch].FrmFull ) 
								{
									Uart[Ch].EleSn = j;	//记录下本次调用处理到第几个元素
									break; //满一帧
								}
								
								if( Temp08 ) break;
							}
						}
						
						if( ComRet.DAR ) break;
						if( (0 == Temp08) || ((CHIN == Ch) && (2 == Temp08)) ) Ret.Value += ComRet.AckLen; //用于关联对象冻结
					}
				}
			}
		}
		
		if( Oi[2] ) break;
	}

	Ret.AckLen = Uart[Ch].Total698-k;
//	Ret.DoneLen = 4;
	Ret.DAR = DAR_SUCCESS; //成功
	
	return Ret;
}


RetFrame SetNormal( uint08 Ch, unsigned char *Frame, unsigned char Set )
{
	unsigned char i, j, n, Temp08;
	union B16_B08 Temp16;
	unsigned int DoneBytes;
	unsigned char Oi[8];
	unsigned char *RtBuf = Uart[Ch].Buf+16;
	DRW_STRUCT RtPtr; 
	AttrMethod *AMptr;
	unsigned long *DtPtr;
	const unsigned long *EvntPtr;
	RetFrame Ret = {0,0,0,0};
	RetFrame ComRet = {0,0,0,0};
	uint16 curOI;
	unsigned short Loop=0, Offset=0;
	
	CopyApdu( Oi, Frame, 8 );

	Ret.DoneLen += 4; //已处理: OAD
	
//	if( hangup_comm_flag && (Progkey.Timer == 0) )
//	{
//		Ret.DAR = DAR_METERHANGUP;	//挂起
//		return Ret;
//	}
	
	if( Judge_HwAuth(Ch, SET_REQUEST, Oi) )
	{
		Ret.DAR = DAR_REFUSERW;	//拒绝读写
		return Ret;
	}

	if( Set == 0 ) //处于数据格式判断
		Ret.DAR = Security_Judge( Ch, SET_REQUEST, Oi, &Temp08 );
	else
		Ret.DAR = Security_Judge( Ch, 0xff, Oi, &Temp08 );
		
	if( Ret.DAR ) return Ret;
	
	Ret.DAR = 0xFF; //错误代码
	
	AMptr = (AttrMethod *)(MapTab[Temp08].DtType);
	
	i = 0xFF;
	for( n=0; n<20; n++ ) //
	{
		if( 0xFF == AMptr[n].Sn ) break;
		
		if( Oi[2] == (AMptr[n].Sn&0x3F) ) 
		{
			if( 0 == (AMptr[n].Sn&0x40) ) 
			{
				Ret.DAR = DAR_REFUSERW; //拒绝读写
				return Ret;
			}

			i = n;  //在所属类中找到属性编号
		}
	}
	
	curOI = Byte2uShort(Oi);
	if( (Oi[2] < 2) || (((0x4011 == curOI)||(0x4016 == curOI)||(0x4017 == curOI)) && (Oi[3] == 0)) ) //不支持设置：全部属性 or 属性1，公共假日或者时段表不支持索引为0
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}
	else if( ((0xF300 == curOI)||(0xF301 == curOI)) && (Oi[2] == 4) && (Oi[3] != 1) ) //不支持设置：自动轮显 or 按键轮显的允许最大对象数
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}
	else if( (curOI == 0x4300) && (Oi[2] == 10) && Oi[3] )	//电气设备的上报通道，只允许索引为0设置
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}
	else if( (curOI == 0xF101) && (Oi[2] == 3) && Oi[3] ) //显式安全模式参数，只允许索引为00设置
	{
		Ret.DAR = DAR_REFUSERW; //拒绝读写
		return Ret;
	}
//	else if( (curOI == 0x4015) && (Oi[2] == 2) && Oi[3] ) //备用套时区表，只允许索引为00设置
//	{
//		Ret.DAR = DAR_REFUSERW; //拒绝读写
//		return Ret;
//	}
	else
	{
		if( i == 0xFF ) //不支持设置：不存在的属性
		{
			Ret.DAR = DAR_UNEXISTED; //对象不存在
			return Ret;
		}
	}
	
	i += 2;
	
	for( ; i<n+2; i++ )  //属性标识及其特征
	{
		DtPtr = (uint32 *)(AMptr[i-2].Addr); //指向具体的属性数据类型列表
		
		//特殊处理“关联对象列表”设置
		if( (0x30 == Oi[0]) || (0x50 == Oi[0]) )
		{
			EvntPtr = (unsigned long *)(DtPtr[3]);
			
			if( Oi[2] == 3 ) //关联对象列表
			{
		 		//if( Oi[3] || ((Key_Status == 1) && (curOI == 0x3013)) ) //只允许索引为00设置 or 私钥下不允许修改清零事件的关联属性表   liruida q 20241010
				if( Oi[3]  && (curOI == 0x3013))        // liruida q 20241010
				{
					Ret.DAR = DAR_REFUSERW;	
					return Ret;
				}
		 		
		 		//if( Oi[0] == 0x30 ) DtPtr = (uint32*)(&p_ASSOBJ_LIST);             liruida q 20241010
		 		//else DtPtr = (uint32*)(&p_FRZ_ASSOBJLIST);                        liruida q 20241010
			}
		}

		//特殊处理地理位置
		if( 0x4004 == curOI )
		{
			if( (Oi[3] && (Oi[3] != 3) && (Frame[7] > 1)) || ((Oi[3] ==0) && ((Frame[9] > 1) || (Frame[19] > 1))) )
			{
				Ret.DAR = DAR_OVERARRAY;
				return Ret;
			}
		}

		if( T_SCALER_UNIT == DtPtr[0] ) //换算及单位
		{
			Ret.DoneLen += 3; //已处理: 数据类型+换算+单位
			Ret.DAR = DAR_REFUSERW; //拒绝读写
			return Ret;
		}
		else
		{
			if( (T_ARRAY == DtPtr[0]) || (T_STRUCTURE == DtPtr[0]) )
			{
				if( Oi[3] > DtPtr[1] ) //元素索引
				{
					Ret.DAR = DAR_UNEXISTED; //对象不存在
					return Ret;
				}
				
				Loop = GetDataLen( Oi+5, &Offset );

				if( Oi[3] ) //元素索引：1~n单个元素
				{
					Temp16.B08[0] = Oi[3]-1;
					Temp16.B08[1] = Oi[3];
					
					RtPtr.Type = Index2Type( DtPtr, Oi[3] );
				}
				else //元素索引：0全部,
				{
					Ret.DoneLen += 1+Offset; //已处理: 数据类型+元素个数
					
					Temp16.B08[0] = 0;
					Temp16.B08[1] = DtPtr[1];
					
					RtPtr.Type = DtPtr;
				}

				if( Oi[4] != RtPtr.Type[0] ) //数据类型
				{
					Ret.DAR = DAR_DISMATCH; //类型不匹配(7)
					return Ret;
				}
				
				if( Loop != RtPtr.Type[1] )  //元素个数
				{
					if( T_STRUCTURE == Oi[4] )
					{
						Ret.DAR = DAR_OVERARRAY; //越界
						return Ret;
					}
					else if( T_ARRAY == Oi[4] )
					{
						if( Loop && (Loop < RtPtr.Type[1]) )  //元素个数
						{
							if( 0 == Oi[3] ) Temp16.B08[1] = Loop;
						}
						else
						{
							Temp16.B08[1] = 0;
							
							if( ((0x4014 == curOI) || (0x4015 == curOI)) && (0 == Oi[3]) && (Loop > RtPtr.Type[1]) )
								Ret.DAR = DAR_OVERYEARDAY; //时区数超(Bit4)
							else if( ((0x4016 == curOI) || (0x4017 == curOI)) && Oi[3] && (Loop > RtPtr.Type[1]) )
								Ret.DAR = DAR_OVERREGION; //时段数超(Bit5)
							else if( (Loop == 0) && ((0x30 == Oi[0]) || (0x50 == Oi[0])) && (Oi[2] == 3) && (Oi[3] == 0))	//设置关联属性表时，数组数为0表示清空
							{
								if( Set == 1 )
								{
									Uart[Ch].Buf[10] = 0x00;
									Uart[Ch].Buf[11] = EvntPtr[1]; //索引
									Uart[Ch].Buf[12] = Oi[0];

									Uart[Ch].Buf[22] = 0x00; //关联对象个数
									//memset( Uart[Ch].Buf+23, 0, FPAGE_SIZE );           liruida q 20241010
									
									//RefMinute( Ch );     liruida q 20241010
								}
							}
							//显式安全模式参数，Index = 0
							else if( (Loop == 0) && (Oi[3] == 0) && (Oi[2] == 3) && (0xF101 == curOI) )
							{
								if( Set == 1 )
								{
									//InitPermision();    liruida q 20241010
								}
							}
							//电气设备 上报通道，Index = 0
							else if( (Loop == 0) && (Oi[3] == 0) && (Oi[2] == 10) && (0x4300 == curOI) )
							{
								if( Set == 1 )
								{
									j = Mode.Feature1&B0000_1111;
									//UpdateSysPara( 0x80+8, &j, 1 );      liruida q 20241010
								}
							}
							else
								Ret.DAR = DAR_OVERARRAY; //越界
							
							if( Ret.DAR != 0xFF ) return Ret;
						}
					}
				}
			}
			else
			{
				if( Oi[3] )
				{
					Ret.DAR = DAR_UNEXISTED; //对象不存在
					return Ret;
				}
				
				Temp16.B08[0] = 0;
				Temp16.B08[1] = 1;
			}
			
			for( j=Temp16.B08[0]; j<Temp16.B08[1]; j++ ) //属性内元素个数
			{
				RtPtr.Type = Index2Type( DtPtr, (j+1) );

				//特殊处理时区表设置
				if( (Oi[3] == 0) && ((0x4014 == curOI) || (0x4015 == curOI)) )
				{
					Temp16.B08[0] = 0;
					Temp16.B08[1] = 1;
					//RtPtr.Type = (uint32 *)(&p_REGION_TAB);        liruida q 20241010
					Ret.DoneLen -= 2;
				}

				//事件类关联对象列表，Index = 0
				if( (Oi[3] == 0) && (Oi[2] == 3) && (0x30 == Oi[0]) )
				{
					Temp16.B08[0] = 0;
					Temp16.B08[1] = 1;
					//RtPtr.Type = (uint32 *)(&p_ASSOBJ_SET);             liruida q 20241010
					Ret.DoneLen -= 2;
				}

				//冻结类关联对象列表，Index = 0
				if( (Oi[3] == 0) && (Oi[2] == 3) && (0x50 == Oi[0]) )
				{
					Temp16.B08[0] = 0;
					Temp16.B08[1] = 1;
					//RtPtr.Type = (uint32 *)(&p_FRZ_ASSOBJSET);         liruida q 20241010
					Ret.DoneLen -= 2;
				}
				
				//电气设备 上报通道，Index = 0
				if( (Loop >= 2) && (Oi[3] == 0) && (Oi[2] == 10) && (0x4300 == curOI) )
				{
					if( (j == 0) && (Cmp_Data( Frame+Ret.DoneLen, Frame+Ret.DoneLen+5, 5 ) == 3) )
					{
						Ret.DAR = DAR_OTHER; //其它
						return Ret;
					}
				}

				if( (curOI == 0xF101) && (Oi[2] == 3) && (Oi[3] == 0) ) //显式安全模式参数，只允许索引为00设置
				{
					Temp16.B08[0] = 0;
					Temp16.B08[1] = 1;
					//RtPtr.Type = (uint32 *)(&p_ESAMMODE_ARR);    liruida q 20241010
					Ret.DoneLen -= 2;
				}

				RtPtr.RtBuf = Frame+Ret.DoneLen;

				if( Set == 0 ) //处于数据格式判断
					RtPtr.Dir = 2;
				else
					RtPtr.Dir = 1;
				RtPtr.OutBuf = Uart[Ch].Buf+22;
				DoneBytes = R_STRUCTURE_ARRAY( &RtPtr );
				if( RtPtr.Result )
				{
					if( ((0x4016 == curOI) || (0x4017 == curOI)) && (0 == Oi[3]) && GetApduByte( Frame+Ret.DoneLen+1 ) 
					&& (DAR_OVERARRAY == RtPtr.Result) && (DoneBytes == 1) )
						Ret.DAR = DAR_OVERREGION; //时段数超(Bit5)
					else
						Ret.DAR = RtPtr.Result;
					return Ret;
				}
				Ret.DoneLen += DoneBytes;
				
				if( Set == 0 ) continue; //处于数据格式判断，不进行参数设置
				
				//------ 组织645帧 ------
				Uart[Ch].Buf[8] = 0x14;
				Uart[Ch].Buf[9] = RtPtr.OutBuf-(Uart[Ch].Buf+10);
				if( 0xFF == *(((uint08 *)(DtPtr+2))+0) ) //数据标识中最低字节为FF表示需从01开始读取
				{
					memcpy( Uart[Ch].Buf+10, (uint08 *)(DtPtr+2), 4 );
					Uart[Ch].Buf[10] = j+1;
				}
				else
					memcpy( Uart[Ch].Buf+10, (uint08 *)(DtPtr+2+2*j), 4 );

				//特殊处理时区表设置
				if( (Oi[3] == 0) && ((0x4014 == curOI) || (0x4015 == curOI)) )
				{
					Uart[Ch].Buf[10] = 0x00;
				}

				//特殊处理事件类“关联对象列表”设置
				if( (Oi[3] == 0) && (Oi[2] == 3) && (Oi[0] == 0x30) )
				{
					Uart[Ch].Buf[ 9] = 12+(RtPtr.OutBuf-(Uart[Ch].Buf+22))/4; //特殊：长度域=12+关联对象个数
					Uart[Ch].Buf[10] = 0x00;
					Uart[Ch].Buf[11] = EvntPtr[1]; //索引
				}

				//特殊处理冻结类“关联对象列表”设置
				if( (Oi[3] == 0) && (Oi[2] == 3) && (Oi[0] == 0x50) )
				{
					Uart[Ch].Buf[ 9] = 12+(RtPtr.OutBuf-(Uart[Ch].Buf+22))/10; //特殊：长度域=12+关联对象个数
					Uart[Ch].Buf[10] = 0x00;
					Uart[Ch].Buf[11] = EvntPtr[1]; //索引
				}

 				//特殊处理“显式安全模式参数”，只允许索引为00设置
				if( (curOI == 0xF101) && (Oi[2] == 3) && (Oi[3] == 0) )
				{
					Uart[Ch].Buf[10] = 0x00;
				}
				
				memset( Uart[Ch].Buf+14, 0x02, 4 );//密码
				OverCurrChg( Oi, 1 );
				Exchange( Uart[Ch].Buf+18, Oi, 4 );//OAD代替操作者代码
				OverCurrChg( Oi, 0 );
				
				if( Temp16.B08[0] == j )  Uart[Ch].Buf[18] |= 0x80; //允许编程事件记录
				if( (Temp16.B08[1]-j) == 1 ) Uart[Ch].Buf[18] |= 0x40; //允许编程记录
				
				ComRet = FrameProc( Ch, RtBuf ); //命令执行
				if( (ComRet.AckLen == 0) || (RtBuf[0] != 0x00) )
				{
					if( ComRet.AckLen >= 2 )
					{
						switch( RtBuf[1] )
						{
							case 0x04: Ret.DAR = DAR_REFUSERW; break; //拒绝读写
							case 0x10: Ret.DAR = DAR_OVERYEARDAY; break; //时区数超(Bit4)
							case 0x20: Ret.DAR = DAR_OVERREGION; break; //时段数超(Bit5)
							case 0x40: Ret.DAR = DAR_OVERJERR; break; //费率数超(Bit6)
							default: break;
						}
					}
					
					return Ret; //continue
				}
			}
		}
		
		if( Oi[2] ) break;
	}
	
	Ret.DAR = 0; //成功
	Ret.AckLen = 2;	
	return Ret;
}






//读取1个OAD对应的数据
RetFrame GetOadData( uint08 Ch, uint08 *Frame, uint08 Offset, uint08 TF_DAR )
//输入：ApduLen，ApduPtr
//OAD的位置：Frame+ApduPtr
{
	unsigned char Oi[4];
//	unsigned short Len = 0;
	RetFrame Ret = {0,0,0,0};

	//Clear_Wdt();     //liruida q

	OverCurrChg( Frame, 0 );

	CopyApdu( Oi, Frame, 4 );
	
	Ret.DoneLen += 4; //已处理: OAD
	
	if( Judge_HwAuth(Ch, GET_REQUEST, Oi) ) 
	{
		Ret.DAR = DAR_REFUSERW;
	}
	else if( TF_DAR )
	{
		Ret.DAR = TF_DAR;
	}
	else
	{
		if( 5 == InBuf698[0+Ch*MAXRX] )
		{
			if( (1 == InBuf698[1+Ch*MAXRX]) || (2 == InBuf698[1+Ch*MAXRX]) )
			{
				if( (0x30 == Oi[0]) || (0x50 == Oi[0]) )
					//Ret = GetRecord( Ch, Frame );  //liruida q
					return Ret;   //liruida q
				else
					Ret = GetNormal( Ch, Frame );
			}
			else if( (3 == InBuf698[1+Ch*MAXRX]) || (4 == InBuf698[1+Ch*MAXRX]) )
			{
				//Ret = GetRecord( Ch, Frame );   //liruida q
			}
			else
			{
				Ret.DAR = DAR_REFUSERW;
			}
		}
		else if( (6 == InBuf698[0+Ch*MAXRX]) || (7 == InBuf698[0+Ch*MAXRX]) )
		{
			if( 3 == InBuf698[1+Ch*MAXRX] )
			{
				if( (0x30 == Oi[0]) || (0x50 == Oi[0]) )
					//Ret = GetRecord( Ch, Frame );  //liruida q
					return Ret;   //liruida q
				else
					Ret = GetNormal( Ch, Frame );
			}
			else
			{
				Ret.DAR = DAR_REFUSERW;
			}
		}
		else
		{
			Ret.DAR = DAR_REFUSERW;
		}
	}

	OverCurrChg( Frame, 1 );
	
	return Ret;
}


//读取请求
RetFrame GetRequest( uint08 Ch, uint08 *Frame, uint08 *OutBuf )
{
	unsigned short n, ApduLen, ApduPtr;
	unsigned short Loop=0, Offset=0;
	RetFrame Ret = {0,0,0,0};

	switch( Frame[0] ) //请求类型
	{
		case GETREQUESTNORMAL    : //读取一个对象属性请求
			//05 01 04 40 00 02 00
		case GETREQUESTNORMALLIST: //读取若干个对象属性请求
			//05 02 04 02 40 00 02 00 40 01 02 00
		case GETREQUESTRECORD    : //读取一个记录型对象属性请求
			//05 03 1E 30 11 02 00 09 01 00 
		case GETREQUESTRECORDLIST: //读取若干个记录型对象属性请求
			//05 04 1E 02 30 11 02 00 09 01 00 30 12 02 00 09 01 00
			if( (GETREQUESTNORMAL == Frame[0]) || (GETREQUESTRECORD == Frame[0]) )
			{
				Loop = 1;
				ApduPtr = 2;
			}
			else
			{
				Loop = GetDataLen( Frame+2, &Offset ); //待处理的OAD个数
				ApduPtr = 2+Offset;
			}
			
			SendByte( Ch, GET_RESPONSE );
			SendStr ( Ch, Frame, ApduPtr );
			
			ApduLen = ApduPtr+1;
			for( n=0; n<Loop; n++ )
			{
				SendStr( Ch, Frame+ApduPtr, 4 );
				
				Ret = GetOadData( Ch, Frame+ApduPtr, 0, TimeValid );
				if( Ret.AckLen == 0 )
				{
					if( Ret.DAR == 0 ) Ret.DAR = DAR_UNEXISTED; //对象不存在
					
					if( ((3 == Frame[0]) || (4 == Frame[0])) ) 
					{
						SendByte( Ch, 0x00 ); //RCSD = NULL
						Ret.AckLen += 1;
					}
					SendByte( Ch, 0x00 ); //DAR
					SendByte( Ch, Ret.DAR );
					
					Ret.AckLen += 2;
				}
				
				if( CalApduLen( Ch, ApduLen+4+Ret.AckLen ) ) break; //返回帧超APDU最大尺寸
			
				ApduLen += (4+Ret.AckLen);
				ApduPtr += Ret.DoneLen;
			}

			Uart[Ch].Total698 = ApduLen;
			if( (GETREQUESTNORMALLIST == Frame[0]) || (GETREQUESTRECORDLIST == Frame[0]) )
			{
				if( Loop < 0x80 )
				{
				}
				else if( Loop < 0x100 )
				{
					if( n < 0x80 )
					{
						MoveForword( OutBuf+4, 1, Uart[Ch].Total698-5 );
						Uart[Ch].Total698 -= 1;
					}
				}
				else
				{
					if( n < 0x80 )
					{
						MoveForword( OutBuf+4, 2, Uart[Ch].Total698-6 );
						Uart[Ch].Total698 -= 2;
					}
					else if( n < 0x100 )
					{
						MoveForword( OutBuf+5, 1, Uart[Ch].Total698-6 );
						Uart[Ch].Total698 -= 1;
					}
				}
				
				if( n < 0x80 )
				{
					PutApduByte( OutBuf+3, n );
				}
				else if( n < 0x100 )
				{
					PutApduByte( OutBuf+3, 0x81 );
					PutApduByte( OutBuf+4,    n );
				}
				else
				{
					PutApduByte( OutBuf+3, 0x82 );
					PutApduByte( OutBuf+4, (n>>8)&0xFF );
					PutApduByte( OutBuf+5, (n>>0)&0xFF );
				}
			}

			Ret.AckLen = Uart[Ch].Total698;
			break;
			
//		case GETREQUESTNEXT      : //读取分帧响应的下一个数据块请求
//			break;

		default: 
//			Ret.DAR = DAR_EEROR; 
			break;
	}

	return Ret;
}

//设置请求
RetFrame SetRequest( uint08 Ch, uint08 *Frame, uint08 *OutBuf )
{
	unsigned short k=0, n, Len, ApduLen, ApduPtr;
	unsigned char i=0, Temp08, result;
	RetFrame Ret = {0,0,0,0};
	unsigned char Depth;
	unsigned short Loop=0, Offset=0, DarPos;
	
	switch( Frame[0] )
	{
		case SETREQUESTNORMAL: //设置一个对象属性请求
			//06 01 04 40 00 02 00 1C 07 E2 0C 19 13 19 26 
		case SETREQUESTNORMALLIST: //设置若干个对象属性请求
			//06 02 04 02 40 00 02 00 1C 07 E2 0C 19 13 19 26 40 0C 02 05 11 06 
		case SETTHENGETREQUESTNORMALLIST: //设置后读取若干个对象属性请求
			//06 03 04 02 40 00 02 00 1C 07 E2 0C 19 13 19 26 40 00 02 00 05 40 0C 02 05 11 06 40 0C 02 05 01 
			if( SETREQUESTNORMAL == Frame[0] )
			{
				Loop = 1;
				ApduPtr = 2;
			}
			else
			{
				Loop = GetDataLen( Frame+2, &Offset ); //待处理的OAD个数
				ApduPtr = 2+Offset;
			}

			SendByte( Ch, SET_RESPONSE );
			SendStr ( Ch, Frame, ApduPtr );
			
			k = ApduPtr+1;
			ApduLen = k;
			for( n=0; n<Loop; n++ )
			{
				//Clear_Wdt();      liruida q 20241010

				if( TimeValid ) Ret.DAR = DAR_TIMEFLAGERR; //时间标签无效
				else  Ret.DAR = DAR_SUCCESS; //默认为成功

				OverCurrChg( Frame+ApduPtr, 0 );
				if( Ret.DAR == 0 ) Ret = SetNormal( Ch, Frame+ApduPtr, 0 ); //格式转换
				if( Ret.DAR == 0 ) Ret = SetNormal( Ch, Frame+ApduPtr, 1 ); //执行设置
				OverCurrChg( Frame+ApduPtr, 1 );
				
				SendStr ( Ch, Frame+ApduPtr, 4 );
				SendByte( Ch, Ret.DAR );
				
				Depth = DefDepth;
				Ret.DoneLen = Type2Len( Frame[4+ApduPtr], Frame+ApduPtr+5, &Depth )+5;
				ApduPtr += Ret.DoneLen;
				
				k += 5; //OAD+DAR
				if( SETTHENGETREQUESTNORMALLIST == Frame[0] )
				{
					SendStr( Ch, Frame+ApduPtr, 4 );
					
					Ret = GetOadData( Ch, Frame+ApduPtr, 1, TimeValid );
					if( Ret.AckLen == 0 )
					{
						if( Ret.DAR == 0 ) Ret.DAR = DAR_UNEXISTED; //对象不存在
						
						if( ((3 == Frame[0]) || (4 == Frame[0])) && (5 == Frame[-1]) ) 
						{
							SendByte( Ch, 0x00 ); //RCSD = NULL
							Ret.AckLen += 1;
						}
						SendByte( Ch, 0x00 ); //DAR
						SendByte( Ch, Ret.DAR );
						
						Ret.AckLen += 2;
					}
					
					ApduPtr += 5; //读取的OAD+延时
					k += (4+Ret.AckLen); //OAD(read)+Data(read)
				}
				
				if( CalApduLen( Ch, k ) ) break; //RAM空间满 or 返回帧超APDU最大尺寸

				ApduLen = k;
				//AssObjFreezed();   liruida q  20241010
			}
			
			Uart[Ch].Total698 = ApduLen;
			
			k = n;
			Temp08 = 0;
			DarPos = 3+Offset;
			for( n=0; n<k; n++ )
			{
				if( GetApduByte( OutBuf+DarPos+4 ) == 0 ) //执行结果成功，做编程记录
				{
					if( Byte2uInt(OutBuf+DarPos) == 0x30120300 ) 
					{
						Temp08 = 0;
						//Clr_Record( ee_programn_inpage ); //清除该冻结对象的历史记录   liruida q 20241010
					}
					
					if( Temp08 == 0 )
					{
						if( first_prog_flag == 0 )	//需要重新增加一条编程记录
						{
							Temp08 = 1;
							first_prog_flag = 1;	//继续本次编程记录
							//CopyApduInv( Eeprom.Buffer+6, OutBuf+DarPos, 4 ); //操作者代码(4)          liruida q 20241010
							//memset( Eeprom.Buffer+10, 0xFF, 40 ); //填充为FF                       liruida q 20241010
							//Event_Record(ee_programn_inpage);     liruida q  20241010
						}
						else
						{
							Temp08 = 2;
							//i = Read_Event_Point(ee_programn_inpage);   liruida q 20241010
							//I2C_Read_Eeprom( ee_program_note_page+i, ee_programnote_inpage, Eeprom.Buffer, ee_programnote_lenth );	//时间        liruida q 20241010
						}
					}
					
					//MoveBackword( Eeprom.Buffer+10, 4, 36 ); //循环移位       liruida q 20241010
					//CopyApduInv( Eeprom.Buffer+10, OutBuf+DarPos, 4 ); //数据标识(4)               liruida q 20241010
				}
				
				DarPos += 5; //OAD(set)+DAR(set)
				if( SETTHENGETREQUESTNORMALLIST == Frame[0] )
				{
					unsigned char Depth, Choice;
					
					Choice = OutBuf[ DarPos+4 ]; //CHOICE = 0:无数据; 1:有数据
					DarPos += 5; //OAD(read)+CHOICE
					if( 1 == Choice ) //有数据
					{
						Depth = DefDepth;
						Len = Type2Len( OutBuf[ DarPos ], OutBuf+DarPos+1, &Depth )+1;
						DarPos += Len;
					}
				}
			}
			
			if( Temp08 )
			{
				//result = Read_Event_Point(ee_programn_inpage);   liruida  q  20241010
				//I2C_Write_Eeprom( ee_program_note_page+result, ee_programnote_inpage, Eeprom.Buffer, ee_programnote_lenth );	//时间         liruida q 20241010
			}

			if( SETREQUESTNORMAL != Frame[0] )
			{
				n = k;
				if( Loop < 0x80 )
				{
				}
				else if( Loop < 0x100 )
				{
					if( n < 0x80 )
					{
						MoveForword( OutBuf+4, 1, Uart[Ch].Total698-5 );
						Uart[Ch].Total698 -= 1;
					}
				}
				else
				{
					if( n < 0x80 )
					{
						MoveForword( OutBuf+4, 2, Uart[Ch].Total698-6 );
						Uart[Ch].Total698 -= 2;
					}
					else if( n < 0x100 )
					{
						MoveForword( OutBuf+5, 1, Uart[Ch].Total698-6 );
						Uart[Ch].Total698 -= 1;
					}
				}
				
				if( n < 0x80 )
				{
					PutApduByte( OutBuf+3, n );
				}
				else if( n < 0x100 )
				{
					PutApduByte( OutBuf+3, 0x81 );
					PutApduByte( OutBuf+4,    n );
				}
				else
				{
					PutApduByte( OutBuf+3, 0x82 );
					PutApduByte( OutBuf+4, (n>>8)&0xFF );
					PutApduByte( OutBuf+5, (n>>0)&0xFF );
				}
			}
			
			Ret.AckLen = Uart[Ch].Total698;
			break;

		default: 
			break;
	}

	return Ret;
}


unsigned char DataIntegrity( unsigned char Ch, unsigned char *Frame )
{

	return 0; //数据完整  //liruida q
}




RetFrame Apdu_Proc( unsigned char Ch, unsigned char *ApduBuf, unsigned char *OutBuf698 )
{
	unsigned char Temp08, TempP;
	RetFrame Ret = {0,0,0,0};
	
	Ret.DAR = DataIntegrity( Ch, ApduBuf ); //数据完整性分析
	if( Ret.DAR ) //异常报文响应
	{
		SendByte( Ch, EEROR_RESPONSE);	//异常响应
		SendByte( Ch, ApduBuf[2]);	//PIID
		SendByte( Ch, Ret.DAR&0x0f);	//DAR
		Ret.AckLen = Uart[Ch].Total698;
		return Ret;
	}

	Temp08 = ApduBuf[0];//暂存解析后的服务请求命令
	
	TempP = progenable;  
	progenable = 1;	//编程使能,兼容645   
	
	switch( Temp08 )	//应用层服务
	{
			
		case GET_REQUEST       :  //读取请求
			Ret = GetRequest( Ch, ApduBuf+1, OutBuf698 );
			break;
		case SET_REQUEST       :  //设置请求
			Ret = SetRequest( Ch, ApduBuf+1, OutBuf698 );
			break;
			
		default: 
			break;
	}
	
	if( TempP ) progenable = 1;
	else progenable = 0;
		
	return Ret;
}




RetFrame Apdu_Ack( unsigned char Ch )
{
	unsigned int k;
	unsigned char result, Buf[2];
	RetFrame Ret = {0,0,0,0};
	unsigned char ecode ReportInf[] = { 0x01, 0x01, 0x01, 0x33, 0x20, 0x02, 0x01, 0x01, 0x51 };//仅跟随上报事件
	unsigned char ecode ReportInf1[] = { 0x01, 0x01, 0x01, 0x20, 0x15, 0x02, 0x00, 0x01, 0x04, 0x20 };//仅跟随上报状态字
	unsigned char ecode ReportInf2[] = { 0x01, 0x01, 0x02, 0x33, 0x20, 0x02, 0x01, 0x01, 0x51 };
	unsigned char ecode ReportInf21[] = { 0x20, 0x15, 0x02, 0x00, 0x01, 0x04, 0x20 };

	if( (0 == (Mode.Feature1&0x04)) || (Ch == CHHW) || (((0 == ModeEx.RptMode[8]) || (0 == Reportstatus[Ch])) && (0 == FollowReport[Ch])) ) //目前红外不支持跟随上报
	{
		SendByte( Ch, 0 ); //跟随上报信息
	}
	else if( ((Ch==CH485)&&((Mode.Feature1&0x30)==0x00)) || ((Ch==CHZB)&&((Mode.Feature1&0xc0)==0x00)) )//判断上报通道
	{
		SendByte( Ch, 0 ); //跟随上报信息
	}
	else if( (Ch==CHZB) && (AckBuf698[Ch*MAXRX]==0x88) )//主动上报命令中不用带跟随上报
	{
		SendByte( Ch, 0 ); //跟随上报信息
	}
	else
	{
		if( FollowReport[Ch] )
		{
			if( (0 == Reportstatus[Ch]) || (0 == ModeEx.RptMode[8]) ) SendStr( Ch, ReportInf, sizeof(ReportInf) );
			else SendStr( Ch, ReportInf2, sizeof(ReportInf2) );
			
			SendByte( Ch, 0x30 );
			SendByte( Ch, FollowReport[Ch] );
			if( 0x05 == FollowReport[Ch] )
				SendByte( Ch, 0x07 );
			else
				SendByte( Ch, 0x02 );
			SendByte( Ch, 0x00 );
		}
		
		if( Reportstatus[Ch] && ModeEx.RptMode[8] )
		{
			if( 0 == FollowReport[Ch] ) SendStr( Ch, ReportInf1, sizeof(ReportInf1) );
			else SendStr( Ch, ReportInf21, sizeof(ReportInf21) );
			
			Buf[0] = Reportstatus[Ch];
			BitInverse( Buf, 1 );
			Buf[1] = Reportstatus[Ch]>>8;
			BitInverse( Buf+1, 1 );
			SendByte( Ch, Buf[0] );
			SendByte( Ch, Buf[1] );
			SendByte( Ch, 0x00 );
			SendByte( Ch, 0x00 );

			if( Reportstatus[Ch] != Reportsta_Bk[Ch] )
			{
				Reportsta_Bk[Ch] = Reportstatus[Ch];
				//Store_Reportstatus(Ch);   liruida q 20240918
			}
		}
	}
	
	if( 0 == TimeTag[0] )  //时间标签
		SendByte( Ch, 0 );
	else
		SendStr( Ch, TimeTag, 11 );
	
	Ret.AckLen = Uart[Ch].Total698;

	//组织响应帧
	// liruida q 20240918
	//Security_Type: 0xFF：非安全模式传输; 0/1:执行结果正常的安全传输; 其他值：执行结果异常的安全传输
	if( (Security_Type != 0xff) && (Security_Type >= 2) )//安全传输报错
	{
		AckBuf698[0+Ch*MAXRX] = SECURITY_RESPONSE;
		AckBuf698[1+Ch*MAXRX] = 2;//错误，DAR
		AckBuf698[2+Ch*MAXRX] = Security_Type;
		AckBuf698[3+Ch*MAXRX] = 0;//	无安全信息
		
		Security_Type = 1;
		Uart[Ch].Total698 = 4;
	}

	Uart[Ch].ApduLen = Uart[Ch].Total698; //待发送总字节数

	return Ret;
}


void Uart_SendProcess_698( unsigned char Ch, unsigned char *OutBuf, unsigned int Len )
{
	uint16 i, k, Temp;
  	uint08 *pTemp08;   //liruida  20240926
	
  	k = 0;
	Uart[Ch].TxBuf[k++] = 0x68;

	if(	Uart[Ch].Ctrl_698_Tx & B0010_0000 ) //控制域bit5：多帧传输
		Temp = 17+Len;
	else
		Temp = 15+Len;
	
	Uart[Ch].TxBuf[k++] = Temp;
	Uart[Ch].TxBuf[k++] = Temp>>8;
	
	Uart[Ch].TxBuf[k++] = Uart[Ch].Ctrl_698_Tx; //控制码
	Uart[Ch].TxBuf[k++] = 0x05;//地址标志AF,暂时固定地址长度为6字节
	
//	Comm_Addr.Comm_Id[0] = 0x11;  //   liruida 20240920
//	Comm_Addr.Comm_Id[1] = 0x11;
//	Comm_Addr.Comm_Id[2] = 0x11;
//	Comm_Addr.Comm_Id[3] = 0x11;
//	Comm_Addr.Comm_Id[4] = 0x11;
//	Comm_Addr.Comm_Id[5] = 0x88;
	
	memcpy(Comm_Addr.Comm_Id, pstParm->Terminal.Struct.TermInfo.Struct.TermAddr, 6);
	
	Exchange( Uart[Ch].TxBuf+k, Comm_Addr.Comm_Id, 6 );//服务器地址
	k += 6;
	Uart[Ch].TxBuf[k++] = Uart[Ch].Clt_Addr_Tx;//客户机地址
	
	
	
	//pTemp08 = &Uart[Ch].TxBuf[1];    // liruida 20240926
	//Uart[Ch].FCS_Tx.B16 = Crc_16Bits_698( Uart[Ch].FCS_Tx.B16^0xFFFF, &Uart[Ch].TxBuf[1], k-1 );
	Uart[Ch].FCS_Tx.B16 = Crc_16Bits_698( 0xFFFF, &Uart[Ch].TxBuf[1], k-1 );

	//Uart[Ch].TxBuf[12] = Uart[Ch].FCS_Tx.B08[0];
	//Uart[Ch].TxBuf[13] = Uart[Ch].FCS_Tx.B08[1];

	
	
	//帧头校验HCS
	Uart[Ch].TxBuf[k++] = Uart[Ch].FCS_Tx.B08[0];
	Uart[Ch].TxBuf[k++] = Uart[Ch].FCS_Tx.B08[1];
	
	if(	Uart[Ch].TxBuf[3] & B0010_0000 ) //控制域bit5：多帧传输
	{
		Uart[Ch].TxBuf[k++] = Uart[Ch].ApduFrameNo;
		Uart[Ch].TxBuf[k++] = Uart[Ch].ApduFrameNo>>8;
	}
  	
	memcpy( Uart[Ch].TxBuf+k, OutBuf, Len );
	k += Len;
	
	if( Uart[Ch].TxBuf[3] & B0000_1000 ) //扰码标志位SC=1
	{
		for( i=9+(Uart[Ch].TxBuf[4]&0x0F); i<k; i++ )
			Uart[Ch].TxBuf[i] += 0x33;
	}
	
	//Uart[Ch].FCS_Tx.B16 = Crc_16Bits_698( Uart[Ch].FCS_Tx.B16^0xFFFF, &Uart[Ch].TxBuf[1], k-1 );
	Uart[Ch].FCS_Tx.B16 = Crc_16Bits_698( 0xFFFF, &Uart[Ch].TxBuf[1], k-1 );
	
	//帧校验FCS
	Uart[Ch].TxBuf[k++] = Uart[Ch].FCS_Tx.B08[0];
	Uart[Ch].TxBuf[k++] = Uart[Ch].FCS_Tx.B08[1];
	Uart[Ch].TxBuf[k++] = 0x16;
	

	
	for (int i = k; i >= 0; --i) 
	{
		Uart[Ch].TxBuf[i + 4] = Uart[Ch].TxBuf[i];
	}

	// 将前四个位置设置为0xFE
	for (int i = 0; i < 4; ++i) 
	{
		Uart[Ch].TxBuf[i] = 0xFE;
	}

	
	Uart[Ch].Total_Tx = 4+k; //前导4字节FE liruida 20240920
	Uart[Ch].Transfer = 0;
//	Uart[Ch].Flag |= B1000_0000;//规约处理结束准备发送数据标志
}



RetFrame Apdu_Pre( uint08 Ch )
{
	RetFrame Ret = {0,0,0,0};

	Security_Type = 0xff;//默认正常传输
	Security_Mode = 0xff;//安全模式字：bit7=1密文，bit7=0明文，bit6~0为数据验证信息选择类型
	
	if( (InBuf698[0+Ch*MAXRX] == SECURITY_REQUEST )   //安全请求
	 || (InBuf698[0+Ch*MAXRX] == SECURITY_RESPONSE) ) //安全响应
	{
		//Ret = SecurityRequest( Ch, InBuf698+Ch*MAXRX );	//会话处理    liruida
		if( Ret.AckLen == 0 )
		{
			Security_Mode = 0xff;
			if( ConectType[Uart[Ch].Client][Ch] != 2 ) Security_Type = DAR_AUTHFAIL;	//未建立对称签名链接,安全认证失败
			else if( Ret.DAR == DAR_METERHANGUP ) Security_Type = DAR_METERHANGUP;	//挂起
			else Security_Type = DAR_ENCRYPTERR;	//对称解密错误
		}
		
		if( Security_Type > 1 ) InBuf698[0+Ch*MAXRX] = SECURITY_REQUEST;//异常
	}

	return Ret;
}

void GetApduFrame( unsigned char Ch )
{
	unsigned char Temp08;
	unsigned short Len;
	
	MaxApduLen[Ch] = DefMaxApduLen[Ch];
	
	Temp08 = 0; //帧是否有效：0-无效; 1-有效
	
	Uart[Ch].ApduPos = (9+Uart[Ch].Buf[4]&0x0F); //记录下链路层用户数据的起始地址
	memcpy( (uint08*)(&Len), Uart[Ch].Buf+1, 2 );
	Len -= (4+Uart[Ch].ApduPos-3); //此帧中数据域字节数
	
	if( (Uart[Ch].Buf[3]&0x20) == 0 ) //单帧传输
	{
		if( Len <= DefMaxApduLen[Ch] )
		{
			Uart[Ch].Ctrl_698 = Uart[Ch].Buf[3]; //控制码
			Uart[Ch].Client_Addr = Uart[Ch].Buf[6+(Uart[Ch].Buf[4]&0x0F)];
				
			Uart[Ch].Flag &= B1100_1111;
			Uart[Ch].Flag |= ((Uart[Ch].Buf[4]&B1100_0000)>>2); //地址类型

			Uart[Ch].ApduStatus = 5; //帧处理
			
			Uart[Ch].ApduPtr = Len;
			
			memcpy( InBuf698+Ch*MAXRX, Uart[Ch].Buf+Uart[Ch].ApduPos, Len );  //liruida 以上步骤解析并存储数据链路层数据，并指向APDU位置
			Temp08 = 1;
		}
	}
	else //分帧传输
	{
		memcpy( Uart[Ch].SubFrame.B08, Uart[Ch].Buf+Uart[Ch].ApduPos, 2 );
		Uart[Ch].ApduPos += 2;
		Len -= 2;
		
		switch( (Uart[Ch].SubFrame.B16>>8)&B1100_0000 ) //分帧类型bit15:14: 起始帧00, 确认帧10, 最后帧01, 中间帧11
		{
			case B0000_0000: //分帧传输数据起始帧
				if( 0 != (Uart[Ch].SubFrame.B16&0x0FFF) ) break; //帧序号相等
				if( Len > DefMaxApduLen[Ch] ) break;
				
				Uart[Ch].Ctrl_698 = Uart[Ch].Buf[3]; //控制码
				Uart[Ch].Client_Addr = Uart[Ch].Buf[6+(Uart[Ch].Buf[4]&0x0F)];
				
				Uart[Ch].Flag &= B1100_1111;
				Uart[Ch].Flag |= ((Uart[Ch].Buf[4]&B1100_0000)>>2); //地址类型
				
				memcpy( InBuf698+Ch*MAXRX, Uart[Ch].Buf+Uart[Ch].ApduPos, Len );
				Uart[Ch].ApduPtr = Len;
				
				//发送确认帧
				Uart[Ch].ApduFrameNo = 0x8000;
				
				Uart[Ch].ApduStatus = 2; //收多帧
				Uart[Ch].Ctrl_698_Tx = Uart[Ch].Ctrl_698|0x80;
				Uart[Ch].Clt_Addr_Tx = Uart[Ch].Client_Addr;
				Temp08 = 1;
				break;
				
			case B1000_0000: //分帧传输确认帧
				if( 4 != Uart[Ch].ApduStatus ) break; //多帧发送时才允许确认帧
				if( (Uart[Ch].ApduFrameNo&0x0FFF) != (Uart[Ch].SubFrame.B16&0x0FFF) ) break; //帧序号加1
				
				//发送下一帧
				Uart[Ch].ApduFrameNo++;
				
				Temp08 = 1;
				break;

			case B1100_0000: //分帧传输中间帧
			case B0100_0000: //分帧传输最后帧
				if( 2 != Uart[Ch].ApduStatus ) break; //收到起始帧才允许中间帧
				if( ((Uart[Ch].ApduFrameNo+1)&0x0FFF) != (Uart[Ch].SubFrame.B16&0x0FFF) ) break; //帧序号加1
				if( (Uart[Ch].ApduPtr+Len) > DefMaxApduLen[Ch] ) break;

				memcpy( InBuf698+Ch*MAXRX+Uart[Ch].ApduPtr, Uart[Ch].Buf+Uart[Ch].ApduPos, Len );
				Uart[Ch].ApduPtr += Len;
				
				if( ((Uart[Ch].SubFrame.B16>>8)&0xC0) == 0xC0 )
				{
					//发送确认帧
					Uart[Ch].ApduFrameNo++;
				}
				else
				{
					//帧接收完毕, 调用APDU处理
					Uart[Ch].ApduStatus = 5; //帧处理
					Uart[Ch].Ctrl_698 &= B1101_1111; //清除多帧标志
				}
				
				Temp08 = 1;
				break;
				
			default:
				break;
		}
	}
	
	if( 0 == Temp08 )
	{
		Uart[Ch].ApduPtr = 0; //APDU中已处理到何处(分帧接收)
		Uart[Ch].ApduStatus = 0;
		Uart[Ch].Flag &= B0000_1111;
		Uart[Ch].Response_Timer = 0x00;
		Uart[Ch].Overtime_Timer = 2;//通过超时控制复位通讯
	}
	else
	{
		if( 0 == (Uart[Ch].Client_Addr&0xF0) )
			Uart[Ch].Client = 0; //终端
		else
			Uart[Ch].Client = 1; //主站
	}
}


void Uart_Proc_698( unsigned char Ch )
{

	union B32_B08 OptID;
	RetFrame Ret = {0,0,0,0};
	RetFrame ComRet = {0,0,0,0};
	
	//if( EA_OFF ) return;//掉电不处理,程序直接返回   liruida q
	
	//Adj_Clk_Timer = Adjclk_timer_delay;	//重新启动定时8M时钟调校功能   liruida q
	//if( (Ch==CHZB) && Zb_Comm_Timer ) Zb_Comm_Timer = Zb_Comm_Timer_delay;	//继续启动载波通讯波特率恢复定时器   liruida q
	
	//Successled.Timer = 5+1;	//点灯5s   liruida q
	
	GetApduFrame( Ch ); //数据从链路层搬到应用层APDU中
	
	
	if( 5 == Uart[Ch].ApduStatus ) //帧处理
	{
		Uart[Ch].Total698 = 0;
		Uart[Ch].ApduFrameNo = 0;
		
		Uart[Ch].EleSn = 0;
		Uart[Ch].FrmFull = 0;
		
		TimeValid = 0;
		memset( TimeTag, 0x00, 11 ); //初始化时间标签
		
		if( B0100_0011 != (Uart[Ch].Ctrl_698&B1100_0111) ) Uart[Ch].Flag |= 0x30;
		
		Ret = Apdu_Pre( Ch );
		
		ComRet = Apdu_Proc( Ch, InBuf698+Ch*MAXRX, AckBuf698+Ch*MAXRX );
//		if( (ComRet.Value == 0x99EE) && ((Uart[Ch].Flag&0x30) != 0x30) ) return;
		
		Exchange( OptID.B08, AckBuf698+3+Ch*MAXRX, 4 ); 
		
		if( (Uart[Ch].Flag&0x30) != 0x30 ) Ret = Apdu_Ack( Ch );      //liruida q

		Uart[Ch].Ctrl_698_Tx = Uart[Ch].Ctrl_698|0x80;
		Uart[Ch].Clt_Addr_Tx = Uart[Ch].Client_Addr;
		
		if( LinkTimer[Uart[Ch].Client][Ch] ) //应用连接超时时间，在每次通信时重新开始计时
			LinkTimer[Uart[Ch].Client][Ch] = Byte2uInt(&ConectInfor[Uart[Ch].Client][Ch][33]);
		
		if( ComRet.Value == 0x88DD ) 
		{
			//InitConectInfor(Ch);         //liruida q
			//Clear_Rand_Gene(); //断开应用链接，复位ESAM           //liruida q
		}
	}
	
	Uart[Ch].Flag &= ~(B0100_0000);

	if( (Uart[Ch].Flag&0x30) == 0x30 ) //广播地址
	{
		Uart[Ch].ApduPtr = 0; //APDU中已处理到何处(分帧接收)
		Uart[Ch].ApduStatus = 0;
		Uart[Ch].Overtime_Timer = 2;//通过超时控制复位通讯
	}
	else
	{
		Uart[Ch].Flag |= B1000_0000; //规约处理结束准备发送数据标志
	}
	
	if( Uart[Ch].ApduStatus != 4 ) //非多帧发送期间
	{
		if( ComRet.Value == 0x55aa )	//清零
		{
			//Clear_Meter( Ch, OptID.B08 );	//0x1a清零命令或者钱包初始化命令     //liruida q  
		}
	}
}


/**
 * @brief 检查帧地址是否匹配本机地址
 * @param[in] pFrame        帧
 * @param[in] pAddr         地址
 * @retval  出错返回 PTL_RET_ERROR，正常返回帧长度
 */

bool DLT698_FrameAddrMatch(unsigned char* pFrame, unsigned char* pAddr)
{
    return true; //检查698规约地址是否匹配本机地址
}



/**
 * @brief DLT698_初始化
 * @param[in] void
 * @retval void
 */
bool DLT698_Init(void)
{
    int i;

    for (i = 0; i < DLT698_PTL_HANDLE_NUM; i++)
    {
        stDlt698Rcv[i].ucStep = DLT698_RCV_START;
        stDlt698Rcv[i].dwRcvLen = 0;
    }

    return true;
}

/**
 * @brief 重置收帧
 * @param[in] udwHandle        句柄，唯一值。且必须小于DLT698_PTL_HANDLE_NUM
 * @retval 是否成功
 */
bool DLT698_Reset(PTL_HANDLE udwHandle)
{
    udwRcvtimerCounter[udwHandle] = 0;              //接收延时计数器=0
    stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;//DLT698_接收步骤为开始接收
    stDlt698Rcv[udwHandle].dwRcvLen = 0;            //接收帧长度为=0 
    return true;
}



/**
 * @brief 从串口缓冲区中接收698规约链路层帧(所有帧的数据)
 * @param[in]  udwHandle        句柄，唯一值。且必须小于DLT698_PTL_HANDLE_NUM
 * @param[out] ucBuf            存放收到的内容
 * @param[in]  FunGetBytes      底层接口
 * @retval  接收到帧返回帧长，接收中返回0, 出错返回PTL_RET_ERROR
 */
static int DLT698_FrameRecvING(PTL_HANDLE udwHandle, unsigned char *pucBuf, PTL_PORT_GET_BYTES FunGetBytes)
{
    int dwLen = 0;
    //检查合法性
    if (pucBuf == NULL || FunGetBytes == NULL || udwHandle >= DLT698_PTL_HANDLE_NUM)
    {//不合法,错误处理
        dwLen = PTL_RET_ERROR;
    }
    else
    {//合法
        switch(stDlt698Rcv[udwHandle].ucStep)
        {//根据DLT698_接收步骤散转
            case DLT698_RCV_START:
            {//开始接收  判断帧头
                if (((dwLen = FunGetBytes(udwHandle, &pucBuf[stDlt698Rcv[udwHandle].dwRcvLen], 1)) == 1) && (pucBuf[0] == DLT698_FRAME_START))
                {//串口中获取一个字节且第一个字节为0x68
                    stDlt698Rcv[udwHandle].dwRcvLen = dwLen;    //接收数据长度为返回字节长度
                    dwLen = 0;
                    stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_LENGTH;  //切换接收步骤为接收长度

                    goto RCV_LENGTH;
                }
                else if (dwLen == PTL_RET_ERROR)
                {
                    dwLen = PTL_RET_ERROR;
                }
                else
                {
                    dwLen = 0;
                }
                break;
            }
            case DLT698_RCV_LENGTH:
            {//接收长度
            RCV_LENGTH:
                if ((dwLen = FunGetBytes(udwHandle, &pucBuf[stDlt698Rcv[udwHandle].dwRcvLen], 2)) == 2)
                {//接收2个字节(长度域,计算报文的长度)
                    stDlt698Rcv[udwHandle].dwRcvLen += dwLen;//之前接收长度+本次接收长度
                    dwLen = 0;
					unsigned char byte1 = pucBuf[1]; 
					unsigned char byte2 = pucBuf[2]; 
					unsigned int hex_value = (byte2 << 8) | byte1;
					int decimal_value = hex_value;
					int len_then1 = decimal_value - 3 + 2;  
					
					stDlt698Rcv[udwHandle].len_then = len_then1;
					
                    stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_CONTENT; //切换接收步骤为接收内容
					
					dwLen = 0;
					
                    goto RCV_CONTENT;   //liruida 20240904
                }
                else if (dwLen == PTL_RET_ERROR)
                {//接收是错误的,就重新开始接收
                    stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;   //切换接收步骤为开始接收
                    dwLen = PTL_RET_ERROR;
                }
                else
                {
                    dwLen = 0;
                }
                break;
            }
			
			case DLT698_RCV_CONTENT:
            {//接收内容
            RCV_CONTENT:
				
				//dwLen = FunGetBytes(udwHandle, &pucBuf[stDlt698Rcv[udwHandle].dwRcvLen], stDlt698Rcv[udwHandle].len_then);
				dwLen = FunGetBytes(udwHandle, &pucBuf[stDlt698Rcv[udwHandle].dwRcvLen], stDlt698Rcv[udwHandle].len_then);  //stDlt698Rcv[udwHandle].len_then = 22
				if (dwLen == PTL_RET_ERROR)
                {
					dwLen = PTL_RET_ERROR;                          //错误
                    stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;//切换接收步骤为开始接收
                }
				
                else if(dwLen != 0)
                {	
					stDlt698Rcv[udwHandle].dwRcvLen += dwLen;//接收长度+
                    dwLen = stDlt698Rcv[udwHandle].dwRcvLen; //接收长度备份   
                    stDlt698Rcv[udwHandle].dwRcvLen = 0;     //接收长度=0   
                    stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;//切换接收步骤为开始接收 为下次接收做准备
                    
					
                }

                break;
            }
           
            default:
            {//出错了
                dwLen = PTL_RET_ERROR;                           //错误   
                stDlt698Rcv[udwHandle].dwRcvLen = 0;             //接收长度=0   
                stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;//切换接收步骤为开始接收
                break;
            }
        }
    }
    return dwLen;
}



/**
 * @brief DLT698_接收698所有桢数据处理
 * @param[in] udwHandle           句柄，唯一值。且必须小于DLT698_PTL_HANDLE_NUM
 * @param[out] pucFrame           数据帧
 * @param[in] pudwLen             帧的长度
 * @param[in] FunGetBytes         底层接口 函数指针
 * @param[in] FunPortReset        底层接口复位,不需要时赋值为Null 函数指针
 * @param[in] udwTimeouts         超时时间
 * @retval
 * @note 不支持97_645
 */

int DLT698_FrameRecv(PTL_HANDLE udwHandle, unsigned char *pucFrame, unsigned int *pudwLen, PTL_PORT_GET_BYTES FunGetBytes, PTL_PORT_GET_BYTES_RESET FunPortReset, unsigned int udwTimeouts)
{
	int dwRcvLen = 0;               //接收到帧的长度
    int eResult;                    //接收状态
    unsigned int udwAllTimeouts;    //超时时间计时器
    unsigned int udwTick, udwDelay;
	
    if (pucFrame == NULL || pudwLen == NULL || FunGetBytes == NULL || udwHandle >= DLT645_PTL_HANDLE_NUM)
    {//合法性检查
        eResult = PTL_RET_ERROR;    //接收状态为错误
    }

    if (udwTimeouts > DLT698_RCV_MAX_TIMEOUTS)
    {//超时限位
        udwAllTimeouts = DLT698_RCV_MAX_TIMEOUTS;
    }
    else
    {
        udwAllTimeouts = udwTimeouts;   //超时时间计时器=超时时间
    }
	
    if (udwRcvtimerCounter[udwHandle] == 0)            /* 此时开始接收数据 */
    {//接收延时计时器=0
        udwRcvtimerCounter[udwHandle] = PROTOCOL_GET_TICK();  //获取当前ms的计数值
        stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;     //接收步骤为开始接收  
        stDlt698Rcv[udwHandle].dwRcvLen = 0;                  //接收数据长度为0  
    }	
	
	dwRcvLen = DLT698_FrameRecvING(udwHandle, pucFrame, FunGetBytes);//从串口缓冲区中接收698规约链路层帧(所有帧的数据)

	for (int i = 0; i < urx_buf_size; ++i) 
	{
        Uart[1].Buf[i] = pucFrame[i];
    }
	
	
    if (dwRcvLen > 0 )        
    {/* 接收到数据 */
        DRV_IO_LED_COM_ONN();                       //通信LED灯亮
        udwRcvtimerCounter[udwHandle] = 0;          //接收延时计时器=0
        *pudwLen = dwRcvLen;                        //备份接收帧的长度
        eResult = PTL_RET_DONE;                     //接收状态为完成   
    }
    else if (dwRcvLen == PTL_RET_ERROR)             
    {/* 接收出错 */
        udwRcvtimerCounter[udwHandle] = 0;          //接收延时计时器=0
        if (FunPortReset != NULL)
        {//需要底层复位 函数指针
            FunPortReset(udwHandle);                /* 复位底层通信口 */
        }
        stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;//切换接收步骤为开始接收
        stDlt698Rcv[udwHandle].dwRcvLen = 0;        //接收帧长度
        eResult = PTL_RET_ERROR;                    //接收状态为错误
    }
    else
    {//接收超时判断
        udwTick = PROTOCOL_GET_TICK();              //获取当前ms的计数值
        /* 防止 tick 溢出 */
        if (udwTick >= udwRcvtimerCounter[udwHandle])
        {//正常计数
            udwDelay = udwTick - udwRcvtimerCounter[udwHandle]; //从接收开始到现在共过了多长时间
        }
        else
        {//循环一圈后计数
            udwDelay = (0xFFFFFFFF - udwRcvtimerCounter[udwHandle] + 1) + udwTick;//从发送开始到现在共过了多长时间
        }
        if (udwDelay > udwAllTimeouts)    /* 检查超时 */
        {
            udwRcvtimerCounter[udwHandle] = 0;      //接收延时计时器=0
            if (FunPortReset != NULL)
            {//需要底层复位
                FunPortReset(udwHandle);            /* 复位底层通信口 */
            }
            stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;//切换接收步骤为开始接收
            stDlt698Rcv[udwHandle].dwRcvLen = 0;    //接收帧长度
            eResult = PTL_RET_TIMEOUTS;             //接收状态为超时         
        }
        else
        {
            eResult = PTL_RET_DOING;                //接收状态为处理中 
        }
        DRV_IO_LED_COM_OFF();                       //通信LED灯灭 
    }    

    return eResult;    

}


/**
 * @brief DLT698_发送
 * @param[in] udwHandle           句柄，唯一值。且必须小于DLT698_PTL_HANDLE_NUM
 * @param[in] pucFrame            要发送的帧
 * @param[in] udwLen              帧的长度
 * @param[in] FunSetBytes         底层接口
 * @param[in] FunPortReset        底层接口复位,不需要时赋值为Null
 * @param[in] udwTimeouts         超时时间
 * @retval
 * @note 该函数需要循环调用，直到返回SND_RESULT_DONE，表示发送结束
 */
int DLT698_FrameSend(PTL_HANDLE udwHandle, unsigned char *pucFrame, unsigned int udwLen, PTL_PORT_SET_BYTES FunSetBytes, PTL_PORT_SET_BYTES_RESET FunPortReset, unsigned int udwTimeouts)
{
    int eResult;        //返回值
    int dwRet;
    static unsigned int udwTimerCounter[DLT645_PTL_HANDLE_NUM] = {0};   //临时存放获取ms的计数值
    unsigned int udwAllTimeouts;
    unsigned int udwTick, udwDelay;

    DRV_IO_LED_COM_ONN();   //打开通信LED灯

    //if (pucFrame == NULL || udwLen < DLT645_FRAME_LENGTH_MIN || FunSetBytes == NULL || udwHandle >= DLT645_PTL_HANDLE_NUM)
	if (pucFrame == NULL || udwLen < 1 || FunSetBytes == NULL || udwHandle >= DLT645_PTL_HANDLE_NUM)
    {//合法性检查 
        eResult = PTL_RET_ERROR;    //返回值为错误
    }

    if (udwTimeouts > DLT698_SND_MAX_TIMEOUTS)
    {//限位
        udwAllTimeouts = DLT698_SND_MAX_TIMEOUTS;
    }
    else
    {
        udwAllTimeouts = udwTimeouts;   //送超时时间给临时超时变量
    }
    if (udwTimerCounter[udwHandle] == 0)            /* 此时开始接收数据 */
    {
        udwTimerCounter[udwHandle] = PROTOCOL_GET_TICK();   //获取当前ms的计数值
    }

    dwRet = FunSetBytes(udwHandle, pucFrame, udwLen);/* 将数据发送出去 */

    if ( dwRet == 0)                    /* 发送完成 */
    {
        udwTimerCounter[udwHandle] = 0;         //临时存放获取ms的计数值=0
        eResult = PTL_RET_DONE;                 //返回值为发送完成
        /* 这里特殊处理，发送后重置接收。后续有问题再修改 为接收做准备*/ 
        udwRcvtimerCounter[udwHandle] = 0;      //超时延时计时器=0
        stDlt698Rcv[udwHandle].ucStep = DLT698_RCV_START;   //DLT698_接收步骤为开始接收
        stDlt698Rcv[udwHandle].dwRcvLen = 0;    //接收帧长度为0
    }
    else if (dwRet == PTL_RET_ERROR)                /* 错误 */
    {//错误处理
        udwTimerCounter[udwHandle] = 0;         //临时存放获取ms的计数值=0
        if (FunPortReset != NULL)
        {
            FunPortReset(udwHandle);                /* 复位底层通信口 清空缓冲区数据*/
        }
        eResult = PTL_RET_ERROR;                //返回值为错误-1
    }
    else
    {//其他情况处理(超时、处理中、不需要应答)
        udwTick = PROTOCOL_GET_TICK();          //获取ms的计数值
        /* 防止 tick 溢出 */
        if (udwTick >= udwTimerCounter[udwHandle])
        {//正常计数
            udwDelay = udwTick - udwTimerCounter[udwHandle];  //从发送开始到现在共过了多长时间
        }
        else
        {//循环一圈后计数
            udwDelay = (0xFFFFFFFF - udwTimerCounter[udwHandle] + 1) + udwTick;//从发送开始到现在共过了多长时间
        }
        if (udwDelay > udwAllTimeouts)    /* 检查超时 */
        {//超时处理
            udwTimerCounter[udwHandle] = 0;//临时存放获取ms的计数值=0
            if (FunPortReset != NULL)
            {
                FunPortReset(udwHandle);    /* 复位底层通信口 清空缓冲区数据*/
            }
            eResult = PTL_RET_TIMEOUTS;     //返回值为超时-4
        }
        else
        {//未超时,就是在处理中
            eResult = PTL_RET_DOING;        //返回值为处理中-2
        }
    }

    return eResult;
}

/**
 * @brief 698帧处理函数（解析）
 * @param[in] udwHandle           句柄，唯一值。且必须小于DLT698_PTL_HANDLE_NUM
 * @param[in] pucFrame            要处理的帧
 * @param[in] udwLen              帧长度
 * @param[out] pucResp            处理结果
 * @retval  正常返回处理结果长度
 */
int DLT698_FrameProc(PTL_HANDLE udwHandle, unsigned char *pucFrame, unsigned int udwLen, unsigned char *pucResp)
{
	int Ch = 1;
	Uart_Proc_698(Ch);   
	
	Uart[Ch].FrmLen = Uart[Ch].ApduLen;
	
	Uart[Ch].Start = 0;
	
	Uart_SendProcess_698( Ch, AckBuf698+Ch*MAXRX+Uart[Ch].Start, Uart[Ch].FrmLen );
	
	Uart[Ch].Start += Uart[Ch].FrmLen; //下次发送的起始地址
	
	//Uart_SendProcess_698( Ch, , Uart[Ch].FrmLen );
	
	for (int i = 0; i < Uart[Ch].Total_Tx; ++i) 
	{
		pucResp[i] = Uart[Ch].TxBuf[i];
    }

	
	return Uart[Ch].Total_Tx;
}


